@hraness/message-like-me 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,633 @@
1
+ # Publish Message Like Me
2
+
3
+ Message Like Me builds one exact public package tarball, validates those bytes
4
+ on macOS and Linux, and publishes the same tarball plus `SHA256SUMS` to an
5
+ immutable GitHub Release. Only then does it publish that tarball to npm through
6
+ trusted publishing. Its informational site can enter Vercel Production only
7
+ after both public coordinates pass admission. The tag workflow never receives
8
+ the production-ref writer key. A separate current-`main` workflow admits the
9
+ external npm and GitHub artifacts, then advances the production source after
10
+ the Release succeeds. A dedicated private Hraness GitHub App signs one
11
+ exact-commit status; the same protected job's scoped GitHub Actions token makes
12
+ the leased ref move only while the matching App-sourced success is current.
13
+
14
+ No personal access token, deploy key, Vercel token, or repository-administration
15
+ permission belongs in either workflow.
16
+
17
+ ## Establish the production controls once
18
+
19
+ Apply these controls in order. Record the exact readbacks in the change review.
20
+ Do not merge a product or version change until every control and the persistent
21
+ writer canary are complete.
22
+
23
+ The read-only Message Like Me pre-control snapshot on 2026-08-29 is:
24
+
25
+ - authoritative `main` is
26
+ `167738fcc40e523d2696e2ff2bdbe29d502ba7df`;
27
+ - `refs/heads/website-production` is absent;
28
+ - the repository ruleset inventory is exactly empty;
29
+ - Vercel project `prj_K7VHB2ELASGF1OxTCxG8bfxOEoQJ` reports
30
+ `link.productionBranch=main`; and
31
+ - its Production deployment for that exact `main` SHA is `READY` and
32
+ `PROMOTED`.
33
+
34
+ The persisted Message Like Me Sites identifier
35
+ `appgprj_6a88baf1c6388191af90b2e1d7b846ee` is not accessible in the current
36
+ Sites workspace. Preserve it unchanged. Use the canonical Vercel control plane
37
+ for this rollout and do not create a replacement Sites project.
38
+
39
+ 1. Merge the version-neutral release-control change from the reviewed current
40
+ `main` head. Confirm the merged tree is the reviewed tree and all required
41
+ checks passed.
42
+ 2. Create the missing `website-production` ref once at that exact merged
43
+ control commit. This bootstrap is the only manual creation of the ref.
44
+ 3. In the signed-in Vercel project settings for project
45
+ `prj_K7VHB2ELASGF1OxTCxG8bfxOEoQJ`, change Production Branch from `main` to
46
+ `website-production`. The supported project PATCH does not expose this
47
+ field, so use the signed-in provider UI and then perform an exact project
48
+ GET readback. Require `link.productionBranch` to equal
49
+ `website-production`. Preserve the existing project root, build command,
50
+ install command, Git connection, domains, environment, and deployment
51
+ settings.
52
+ 4. Register one private Hraness-owned GitHub App dedicated to Message Like Me
53
+ production authorization. Give the App exactly repository permissions
54
+ `Commit statuses: Read and write` and implicit `Metadata: Read`, with no
55
+ organization permission. Install it on `hraness` with selected-repository
56
+ access to exactly `hraness/message-like-me`. Record its numeric App ID,
57
+ client ID, numeric installation ID, App slug, and the repository's numeric
58
+ ID `1342143606`. These are distinct identities. Read the repository ID from
59
+ GitHub's authenticated repository API and do not substitute a name at the
60
+ token-mint boundary.
61
+ 5. Create environment `production-ref-writer-key`. Limit deployment branches
62
+ to selected branch `main` only. Require reviewer `@0thernet` and leave
63
+ prevent-self-review disabled for this owner-operated release path. Do not add
64
+ a custom deployment-protection-rule App. Store the private key only as
65
+ environment secret `MLM_RELEASE_APP_PRIVATE_KEY`; store checked variables
66
+ `MLM_RELEASE_APP_CLIENT_ID`, `MLM_RELEASE_APP_ID`,
67
+ `MLM_RELEASE_APP_INSTALLATION_ID`, and `MLM_RELEASE_APP_SLUG` in that
68
+ environment. Store the tag Release workflow's exact numeric workflow ID as
69
+ repository variable `MLM_RELEASE_WORKFLOW_ID`, where the unprivileged
70
+ trigger-verification job can read it. The privileged workflow declares
71
+ `environment: { name: production-ref-writer-key, deployment: false }`, so
72
+ admission and secret policy do not create a GitHub Deployment that would
73
+ pollute the exhaustive Vercel Production inventory.
74
+ 6. Add two active repository rulesets whose sole permanent ref target is
75
+ `refs/heads/website-production`:
76
+ - A no-bypass ruleset blocks creation, deletion, and non-fast-forward
77
+ updates. It prevents recreation or force movement after the bootstrap.
78
+ - A separate no-bypass required-status-check ruleset requires context
79
+ `message-like-me/website-production-authority` from the dedicated release
80
+ App's exact numeric App ID. It has no update restriction or bypass actor.
81
+ Bind the expected status source to the App; do not use the client ID,
82
+ installation ID, bot user ID, GitHub Actions Integration `15368`, a human
83
+ identity, an unpinned status context, or a generic deploy-key bypass.
84
+ 7. Add a separate active `main` ruleset requiring pull requests, code-owner
85
+ review for `/.github/workflows/**`, the exact CI checks used by this
86
+ repository, and protection from deletion and non-fast-forward updates. Keep
87
+ bypasses empty.
88
+ 8. Keep active no-bypass ruleset `Immutable version tags` scoped exactly to
89
+ `refs/tags/v*`, with only update and deletion restrictions. It allows a new
90
+ stable tag to be created but prevents an existing release tag from moving or
91
+ disappearing. Read back `current_user_can_bypass=never` before release.
92
+ 9. Enable immutable releases for the repository. Immediately before creating
93
+ each version tag, use owner-admin access out of band to require the repository
94
+ immutable-releases endpoint to report `enabled=true`; record whether owner
95
+ policy also reports `enforced_by_owner`. The Actions token cannot perform
96
+ this administrative read. The workflow must still prove the resulting
97
+ published Release reports `immutable=true` before npm can run.
98
+ 10. Ensure `@hraness/message-like-me` exists publicly under the Hraness npm
99
+ scope, then configure its sole trusted publisher as GitHub Actions repository
100
+ `hraness/message-like-me`, workflow file `release.yml`. Require its exact
101
+ permission set to be `createPackage` plus npm's provider-imposed
102
+ `createStagedPackage`. The checked Release workflow uses only its reviewed
103
+ direct `npm publish` path, never `npm stage` or `stage publish`, and release
104
+ preflight requires the staged-package inventory to be exactly empty. The
105
+ one-time registry bootstrap may publish only the exact already-reviewed
106
+ `v0.8.0` package bytes under the `legacy` dist-tag; every later release must use OIDC
107
+ from the checked workflow. Once trusted
108
+ publishing is proven, disallow traditional token publication for the
109
+ package. This manual `v0.8.0` registry seed is historical bootstrap only.
110
+ The registry may resolve both `legacy` and `latest` to those same immutable
111
+ `0.8.0` bytes. Dist-tags are mutable labels, so sharing that coordinate does
112
+ not alter the historical bootstrap or give it
113
+ trusted-publisher metadata retroactively. Do not rerun its tag or invoke the
114
+ automated Release workflow for `v0.8.0`. After the version-neutral control
115
+ change merges, prepare a separate product pull request for a version newer
116
+ than `0.8.0`; that new version is the first automated OIDC release and
117
+ becomes Latest.
118
+ Never retag or reuse `v0.8.0`. The public repository and package must retain
119
+ automatic npm provenance for every automated release.
120
+
121
+ After setup, use owner-admin access out of band to read back the exact Vercel
122
+ production branch, environment, variables, secret names, complete App
123
+ installation, and all GitHub ref rulesets. Never give that administrative
124
+ credential or evidence collector to the release workflow. Its narrowed App
125
+ token proves only its own effective identity, repository, permission, and
126
+ expiry closure. The Message Like Me post-control record must prove all of these
127
+ assertions together:
128
+
129
+ - `main` is the exact reviewed merge commit for this control change;
130
+ - `website-production` exists at that same commit before its rulesets become
131
+ active;
132
+ - the no-bypass ruleset contains only creation, deletion, and
133
+ non-fast-forward protection for that exact ref;
134
+ - the stable-tag ruleset targets only `refs/tags/v*`, contains only update and
135
+ deletion restrictions, has no bypass actors, and reports
136
+ `current_user_can_bypass=never`;
137
+ - the required-status-check ruleset targets only that exact ref, requires
138
+ context `message-like-me/website-production-authority` from the dedicated
139
+ App's numeric ID, and has no bypass actor;
140
+ - the App installation reports `repository_selection=selected`, account
141
+ `hraness`, exactly `statuses:write` plus `metadata:read`, no `contents` or
142
+ `workflows` authority, and an exhaustive
143
+ `/installation/repositories` set of exactly
144
+ `{hraness/message-like-me}` with repository ID `1342143606`;
145
+ - `production-ref-writer-key` admits only `main`, requires the expected
146
+ reviewer, exposes only the expected key and checked variables, and has no
147
+ custom deployment-protection rules;
148
+ - the Vercel project reads back
149
+ `link.productionBranch=website-production`, while its project root, build,
150
+ install, Git, domain, environment, and deployment settings remain identical
151
+ to the pre-control snapshot; and
152
+ - a later `main` push creates no Vercel Production deployment.
153
+
154
+ Also read back the separate `main` ruleset and prove its pull-request,
155
+ code-owner, exact CI, deletion, and non-fast-forward requirements. The control
156
+ change deliberately retains version `0.8.0` and changes no product claim,
157
+ dependency, lockfile, or generated documentation.
158
+
159
+ Treat the production and canary ruleset IDs and their complete live readbacks as
160
+ an external release gate, not as inputs the promotion workflow may administer.
161
+ The workflow must not create, replace, patch, disable, or broaden a ruleset. A
162
+ release operator revalidates the existing IDs, targets, lifecycle rules,
163
+ App-pinned status context, integration ID, enforcement state, and empty bypass
164
+ sets before admitting a release. Any drift blocks promotion until it is reviewed
165
+ and repaired out of band.
166
+
167
+ ### Bootstrap one workflow-control epoch
168
+
169
+ The routine promotion is intentionally incapable of crossing a change to
170
+ `.github/workflows/**`. Its complete-history gate rejects that range before the
171
+ key environment even though GitHub may allow a contents-capable token to move a
172
+ ref to an existing workflow-changing commit. The permanent App has only
173
+ `statuses:write` plus `metadata:read`; it cannot move any ref. The checked
174
+ workflow must never mint persistent App `contents` or `workflows` authority or
175
+ treat permission omission alone as the workflow-control boundary.
176
+
177
+ When an already-established `website-production` ref predates reviewed workflow
178
+ control changes, perform one separately approved control-epoch bootstrap after
179
+ the target's immutable Release and public npm bytes have passed admission:
180
+
181
+ 1. Record the exact current production SHA, exact release SHA, annotated tag,
182
+ immutable Latest Release, ruleset readbacks, and the complete reviewed commit
183
+ range. Let the routine promotion fail at its workflow-range gate; do not
184
+ approve the key environment for that rejected run.
185
+ 2. In an owner-operated, out-of-band procedure, explicitly authorize a single
186
+ control-epoch credential selected to numeric repository ID `1342143606` with
187
+ only the temporary permissions needed to post the pinned status and move the
188
+ workflow-changing ref. Keep that credential out of Actions and preserve the
189
+ required-status-check and ref-lifecycle rulesets.
190
+ 3. Post the exact App-sourced success status for the release SHA, then use the
191
+ same fixed repository, exact annotated-tag target, and nonempty
192
+ `--force-with-lease=refs/heads/website-production:<expected-old-sha>` contract
193
+ to make exactly one fast-forward. Immediately replace the success with the
194
+ terminal non-success status, revoke the credential, and prove the ref is the
195
+ exact release SHA. Never leave a reusable success context behind.
196
+ 4. Restore and read back the permanent App's exact `statuses:write` plus
197
+ `metadata:read` closure, absence of `contents` and `workflows` authority, and
198
+ singleton repository set. Generate a fresh App private key, replace
199
+ `MLM_RELEASE_APP_PRIVATE_KEY`, and delete the control-epoch key. Routine
200
+ automation must remain paused until both the App downgrade and key rotation
201
+ are proven.
202
+ 5. Dispatch `Promote website production` for the same immutable tag. Because
203
+ the external bootstrap made the ref already exact, recovery stays outside
204
+ `production-ref-writer-key`, mints no token, and accepts only the bounded
205
+ exact-SHA Vercel Production outcome that postdates the Release.
206
+
207
+ That bootstrap closes one workflow-control epoch; it is not precedent for a
208
+ routine broad token, a persistent ref bypass, or an unleased manual ref move.
209
+ Any later release whose newly reachable history contains a workflow-tree change
210
+ starts a new control epoch and requires its own explicit review and
211
+ authorization.
212
+
213
+ ### Prove the split status-and-writer boundary before product release
214
+
215
+ Do not infer the boundary from configuration alone. Before the first product
216
+ release, precreate persistent ref
217
+ `refs/heads/website-production-writer-canary` at the reviewed control commit.
218
+ Apply separate active rulesets with the same no-bypass protections and the same
219
+ App-pinned required status check to that exact canary ref. Prove every side of
220
+ the split credential contract after the App downgrade and key rotation:
221
+
222
+ 1. The negative workflow-delta canary targets a reviewed descendant that
223
+ changes `.github/workflows/**`. The complete-history gate must reject it
224
+ before environment admission and before token minting. Permission omission
225
+ is not the gate: record the complete-history rejection itself.
226
+ 2. The positive non-workflow canary targets a reviewed descendant for which
227
+ every newly reachable commit preserves the baseline workflow-tree OID. Prove
228
+ the status-only App token cannot update the ref and the job-scoped writer
229
+ token cannot update it before the exact App-sourced success exists.
230
+ 3. Post one success status on the exact positive target under context
231
+ `message-like-me/website-production-writer-canary-authority`, prove its exact
232
+ readback, and revoke that short-lived status-only token. With the success
233
+ current, use only the job-scoped writer token to make one fast-forward with
234
+ an explicit nonempty expected-old `--force-with-lease`. Then mint a separate
235
+ status-only token, post and read back the terminal non-success status, and
236
+ revoke that second token.
237
+ 4. Read the exact context back as the distinct terminal `error` after
238
+ consumption, prove a stale lease cannot move the canary, and prove neither
239
+ credential can perform the other credential's role. This evidence proves
240
+ the observed target ended terminal; it does not claim an atomic
241
+ post-consumption update denial that GitHub's status and ref APIs cannot
242
+ express as one transaction.
243
+
244
+ A personal token or deploy key is not an acceptable probe. A bare lease,
245
+ remote-tracking lease, `--force`, empty expected-old, creation, deletion,
246
+ wildcard, or multi-ref push is not acceptable evidence.
247
+
248
+ Capture canonical ruleset, status, and rule-suite evidence that binds every
249
+ probe to the canary ref, status context, numeric App ID, App slug, installation
250
+ ID, before SHA, attempted or accepted after SHA, operation time, and originating
251
+ run. The accepted update must prove the required check came from the pinned App,
252
+ not a name-matching status from another actor, and used no bypass. The negative
253
+ records must prove missing authorization and direct App ref mutation. They must
254
+ also prove stale leases all fail without mutation; the final combined-status
255
+ read must prove the success was replaced by the exact App-authored terminal
256
+ status. Keep the canary ref and
257
+ its dedicated rulesets active after the proof so the evidence remains
258
+ reproducible. The no-bypass deletion rule deliberately forbids deleting it; do
259
+ not attempt deletion or temporarily remove protection.
260
+ Read back that the production rulesets still target only
261
+ `refs/heads/website-production` and the canary rulesets still target only the
262
+ persistent canary ref.
263
+
264
+ Keep the first later product release in a separate pull request based on this
265
+ exact control head. That product pull request must not change
266
+ `.github/workflows/`, `.github/CODEOWNERS`, the provider helpers, or these
267
+ controls. This separation keeps the reviewed control lineage intact.
268
+
269
+ ## Publish a stable release
270
+
271
+ Prepare one stable version commit through a pull request. The root package,
272
+ site package, source version, README install target, and generated site content
273
+ must agree. Create its exact annotated `v<version>` tag only after that commit
274
+ has passed review and entered `main`; the tag commit must remain an ancestor of
275
+ current `main`, and the tag must be the newest stable semantic version. Later
276
+ reviewed `main` descendants do not invalidate the immutable release authority.
277
+ The first automated trusted-publisher version must be newer than the manual
278
+ `v0.8.0` bootstrap coordinate, whether npm currently maps only `legacy` or both
279
+ `legacy` and `latest` to `0.8.0`.
280
+
281
+ The tag-triggered Release workflow:
282
+
283
+ 1. checks out only the requested tag at depth one with tags and persisted
284
+ credentials disabled. Before importing anything else, the checkout must
285
+ contain exactly that local tag ref. A dependency-free helper takes separate
286
+ fixed-URL snapshots of exact `refs/heads/main` and canonical
287
+ `git ls-remote --refs --tags ... refs/tags/v*` output. The combined governed
288
+ inventory is at most 64 KiB and 500 rows and rejects malformed object IDs, non-fully-qualified
289
+ or unexpected refs, duplicate rows, and noncanonical order. Historical
290
+ lightweight stable tags participate in newest-version ordering, but the
291
+ requested tag itself must be one direct annotated tag object whose embedded
292
+ name is exact and whose target is the checked commit. The helper removes
293
+ stale `FETCH_HEAD`, then fetches only fully qualified current `main` into
294
+ `refs/remotes/origin/main` and the requested tag into its same-name local tag
295
+ with `--no-tags`, no configured refspec, no force, no submodules, and no
296
+ `FETCH_HEAD` write. A shallow checkout is unshallowed through only those two
297
+ governed refspecs. The post-import ref set must be exactly those two names and
298
+ both objects must equal the first remote advertisement. The helper rejects
299
+ tag-of-tag and lightweight requested tags, proves the release commit is a
300
+ reviewed ancestor of exact advertised current `main`, and requires an
301
+ identical terminal remote snapshot. The workflow then runs
302
+ the complete root, site, generated-file,
303
+ packed-package, and synthetic macOS gates with read-only permissions;
304
+ 2. creates one npm tarball and `SHA256SUMS`, preserves those exact bytes as a
305
+ 30-day workflow artifact, preserves separate numeric-ID-bound artifacts
306
+ containing only the reviewed dependency-free npm writer and GitHub Release
307
+ writer closures. Both closures are copied from regular non-symlink files into
308
+ fresh runner-temporary roots and checked against exact file inventories before
309
+ any repository code or dependency executes. Every local writer import names its
310
+ `.ts` source explicitly. The workflow also installs the unchanged tarball on
311
+ macOS and Linux;
312
+ 3. gives only the GitHub publication job `contents: write`. That job performs no
313
+ repository checkout or dependency install. Its SHA-pinned Bun and numeric-ID
314
+ artifact actions are part of the privileged TCB. The GitHub token is scoped only to the final
315
+ dependency-free publisher step. The writer artifact
316
+ was assembled from the verified release source by the read-only verification
317
+ job and is bound by its numeric ID and digest. That publisher revalidates the remote
318
+ annotated tag object and reviewed-`main` ancestry, creates or safely resumes
319
+ one deterministic draft, uploads only the tarball and checksum, publishes it
320
+ as Latest, and requires the Release to read back immutable with exact names,
321
+ sizes, digests, and bytes. An ambiguous or non-exact residual draft fails
322
+ closed;
323
+ 4. uses a separate read-only job with pinned Sigstore dependencies to prove the
324
+ immutable Latest GitHub Release and workflow artifact are byte-identical.
325
+ It records its actual run ID and attempt. If the npm version already exists,
326
+ it must contain those exact bytes and its SLSA invocation plus Fulcio
327
+ extension `.21` must bind the same workflow run ID at a positive attempt no
328
+ later than that preflight attempt; and
329
+ 5. gives only the no-checkout npm publication job `id-token: write`. Its
330
+ SHA-pinned Bun, Node, and numeric-ID artifact actions are part of the
331
+ privileged TCB; it installs no repository dependencies before invoking the
332
+ reviewed dependency-free writer. Any later positive attempt of the same run
333
+ may publish a still-absent
334
+ version. If an earlier attempt made the exact version visible before its job
335
+ completed, a later writer performs no mutation and defers acceptance to the
336
+ final read-only provenance gate. A same-attempt absent-to-existing race fails
337
+ closed. The writer records whether it published or observed existing bytes,
338
+ plus its actual run ID and attempt. Final admission requires that exact
339
+ attempt for a publication, or the same run at a positive attempt no later
340
+ than the bounded observation attempt. It also verifies exact npm version and
341
+ Latest integrity, MIT license, SHA-1, SHA-512, GitHub byte parity, and the
342
+ Sigstore bundle's exact repository, workflow, tag, commit, run ID, attempt,
343
+ Fulcio subject, certificate extensions, transparency log, and certificate
344
+ transparency evidence.
345
+
346
+ The immutable annotated tag object, not mutable Release `target_commitish`
347
+ metadata or another branch hint, is the release authority once the tag exists.
348
+ Every reviewed-main comparison binds the exact base commit, merge base,
349
+ `status`, canonical integer `ahead_by` (zero only for identical, positive for
350
+ ahead), zero `behind_by`, and terminal `commits[-1].sha` for an ahead response
351
+ to a branch ref that is read before and after the comparison.
352
+ The workflow never treats an optional `head_commit` response field as authority.
353
+ Re-running or completing a failed workflow never retags,
354
+ deletes an immutable Release, changes tarball bytes, or accepts provenance from
355
+ another run. GitHub publication always precedes npm, preventing a mutable or
356
+ incomplete repository Release from stranding an npm version.
357
+
358
+ The tag workflow has no environment, App credential, provider baseline,
359
+ production-ref mutation, or provider-outcome job. A tag cannot enter
360
+ `production-ref-writer-key` because that environment admits only `main`.
361
+
362
+ After the full Release succeeds on any positive run attempt, its completed
363
+ `workflow_run` starts `Promote website production` from current default-branch
364
+ code. Every promotion checkout uses the exact current-main workflow SHA at
365
+ depth one with tags and persisted credentials disabled. Release content is
366
+ read from the separately imported and verified annotated-tag commit; tagged
367
+ workflow or helper code never executes. Treat the entire upstream payload as
368
+ untrusted. Require the exact
369
+ repository, checked numeric Release workflow ID, workflow name and path,
370
+ upstream event `push`, positive run ID and attempt, successful conclusion,
371
+ stable tag, annotated-tag target, downstream workflow SHA, and reviewed `main`
372
+ ancestry to agree. The current workflow source must still be exact current
373
+ `main`; the immutable release commit may be an earlier reviewed ancestor. A
374
+ manual `workflow_dispatch` with an untrusted release-tag input exists only for
375
+ recovery. Both paths use the same checks. That workflow:
376
+
377
+ 1. runs the same fixed-URL, bounded, double-snapshot ref helper from an exact,
378
+ depth-one, no-tag, no-credential current-`main` checkout whose initial local
379
+ ref set is empty. The helper imports only exact main into
380
+ `refs/remotes/origin/main` and the requested tag into its same-name local tag,
381
+ requires `GITHUB_SHA` to equal advertised current main, and separately binds
382
+ the direct annotated tag's peeled release commit to the successful Release
383
+ run. Its post-import ref set must be exactly those two governed refs. It then
384
+ proves the workflow file, `GITHUB_REF`, current default
385
+ branch, annotated tag object, reviewed ancestry, root and site versions,
386
+ exact npm
387
+ version and Latest integrity, provenance, immutable artifact-complete Latest
388
+ Release, checksum, and release authority all resolve to the same immutable
389
+ release commit and tarball;
390
+ 2. takes two stable, exhaustive GraphQL snapshots of at most 500 current
391
+ `Production` deployments, including each deployment's current state and
392
+ `latestStatus`, bracketed by authenticated GitHub server time and exact
393
+ `website-production` ref reads;
394
+ 3. enters `production-ref-writer-key` with `deployment:false` only when the
395
+ baseline and a separate read-only preflight prove that the ref must advance.
396
+ That preflight first imports complete exact governed history and enumerates
397
+ every commit newly reachable in `<expected-old>..<verified-release>`, capped
398
+ at 250 commits. It rejects shallow or incomplete history, non-fast-forwards,
399
+ malformed or oversized inventories, and any commit whose
400
+ `.github/workflows` tree OID differs from the expected-old baseline. Checking
401
+ every newly reachable commit catches merge-side changes and an edit followed
402
+ by a revert even when the two endpoint trees match. The fresh secret-bearing
403
+ job installs no dependencies; in a step that does not receive the private
404
+ key, it verifies hard-coded SHA-256 pins for the seven reviewed helpers,
405
+ repeats the exact complete-history proof, and emits a bounded receipt binding
406
+ the expected-old SHA, release SHA, commit count and digest, and baseline
407
+ workflow-tree OID. The promotion helper validates that receipt before it may
408
+ enter the App-token lifecycle. A checked local helper then signs a
409
+ bounded RS256 App JWT, authenticates the exact App ID, client ID, slug, and
410
+ organization owner, then reads the checked installation ID and requires its
411
+ selected `hraness` account plus exact `statuses:write` and `metadata:read`
412
+ permission closure. It then POSTs one token request with literal
413
+ `repository_ids: [1342143606]` and only those permissions;
414
+ 4. fails closed unless the mint response contains exactly that numeric
415
+ repository, selected-repository scope, those two permissions, and a
416
+ canonical expiry within the authenticated one-hour response window. It
417
+ masks the token before use and keeps it out of workflow outputs. The checked
418
+ attester posts one `success` status for the exact verified SHA under context
419
+ `message-like-me/website-production-authority`, with no target URL and with
420
+ the status source bound to the dedicated App, proves exact readback, and
421
+ sends exactly one nonredirecting `DELETE /installation/token` for that
422
+ admission token. Only after its bounded revocation convergence may the
423
+ separate job-scoped GitHub Actions credential attempt the leased Git push.
424
+ After that one writer process, a new status-only App token posts a terminal
425
+ `error` under the same context, proves exact readback so the success cannot
426
+ authorize a replay, and is independently revoked. Each DELETE
427
+ requires an HTTP 204 with absent or canonical-zero `Content-Length` and zero
428
+ body bytes, and then observes the exact selected-repository authority until
429
+ two stable authenticated HTTP 401 authorization-denial responses prove
430
+ convergence. A mutation failure and a revocation or convergence failure are
431
+ both retained;
432
+ 5. sandwiches the fresh writer job with separate read-only immutable Release,
433
+ Latest, annotated-tag, reviewed-ancestry, public-artifact, and workflow-source
434
+ admissions; proves `website-production` can fast-forward; then fetches only
435
+ `refs/tags/<verified-tag>` from the fixed HTTPS repository at depth one,
436
+ with tag following and submodule recursion disabled. It peels
437
+ `FETCH_HEAD^{commit}` without checking out or executing tagged code and
438
+ requires the result to equal `verified_sha` before using only the writer
439
+ job's `GITHUB_TOKEN`, passed as `MLM_RELEASE_REF_TOKEN`, to push exactly
440
+ `<verified-sha>:refs/heads/website-production` with
441
+ `--force-with-lease=refs/heads/website-production:<expected-old-sha>`. The
442
+ ref token stays out of URLs, argv, and Git config behind a bounded temporary
443
+ `GIT_ASKPASS` helper. The job token is necessarily available to the hashed
444
+ job code and is also named `GH_TOKEN` for its read-only REST and GraphQL
445
+ calls; only the fixed ref writer reads `MLM_RELEASE_REF_TOKEN`. The status
446
+ attester neither reads nor uses that name, and the App token is never passed
447
+ to the ref writer. Prompting is disabled, global and system configuration
448
+ are disabled, hooks and tags are disabled, cleanup is trapped, and a stale
449
+ lease fails without mutation. The sterile bare repository requires
450
+ `core.repositoryformatversion=0`, `core.bare=true`, and
451
+ `core.filemode=true|false`. Beyond those core keys, it admits only Git's
452
+ filesystem probes: `core.ignorecase=true` when emitted and optional
453
+ `core.precomposeunicode=true|false`. Every other local configuration key is
454
+ rejected before fetch or push. This keeps platform-specific Git
455
+ initialization differences from being mistaken for inherited
456
+ configuration. The exact production-ref
457
+ post-read and independent current-`main` workflow-source revalidation do not
458
+ begin until the terminal status is proven and the App-token wrapper returns
459
+ after its `onRevoked` callback has accepted the sanitized convergence
460
+ receipt. An indeterminate terminal status or revocation therefore prevents
461
+ every post-read; and
462
+ 6. uses a separate read-only job, bounded to 20 minutes, to require exactly one
463
+ new Vercel Production deployment. The deployment and its exhaustive status
464
+ history must bind Vercel bot `35613825`, the exact release SHA, task
465
+ `deploy`, environment `Production`, and a
466
+ `messagelikeme-<deployment>-hraness.vercel.app` URL. Stable terminal tag,
467
+ Release, Latest, workflow-source, ref, inventory, and status readbacks close
468
+ the workflow.
469
+
470
+ The successful DELETE and every accepted HTTP 200 or 401 observation
471
+ require a canonical GitHub `Date` strictly before the minted token's exact
472
+ `expires_at`.
473
+ The monotonic completion of the DELETE anchors a separate 30-second half-open
474
+ request-start window `[start, deadline)`: a response completing exactly at the
475
+ deadline remains eligible, while a later completion fails. The helper may read
476
+ `/installation/repositories` at no more than the ten absolute offsets 0, 250,
477
+ 500, 1,000, 2,000, 4,000, 8,000, 16,000, 24,000, and 29,000 milliseconds. A
478
+ missed slot is skipped rather than retried or shifted, and request, body, and
479
+ sleep latency all consume the same window. App identity, installation, mint,
480
+ DELETE, and observation bodies are streamed under a 1 MiB cap and scrubbed
481
+ after parsing. Every HTTP 200 must still describe the exact singleton selected
482
+ `hraness/message-like-me` repository with ID `1342143606`. Acceptance requires
483
+ two distinct scheduled HTTP 401 authorization-denial reads. An HTTP 403 is
484
+ indeterminate because GitHub can use it for rate limiting or policy denial; it
485
+ never proves revocation. A 200 after either denial, only one denial, any other
486
+ status, a redirect, malformed or oversized body, transport or timing
487
+ ambiguity, or failure to converge within the window fails closed. The exact
488
+ empty HTTP 204 DELETE response is the documented revocation success. The
489
+ scheduled reads are a defense-in-depth check and do not require GitHub to return
490
+ one unique post-revocation denial status. `propagationObserved=false` means the
491
+ first two probes were the stable denial pair; `true` means one or more exact
492
+ authorized 200 responses preceded the final two denials. This 30-second bound is
493
+ a Message Like Me operational ceiling, not a claim about GitHub's
494
+ revocation-propagation SLA. The action is never retried, the full App path is
495
+ capped at seventeen REST requests, and the exact production-ref post-read cannot
496
+ begin until convergence has been reported through the sanitized revocation
497
+ receipt.
498
+
499
+ A runner cancellation, host loss, or indeterminate status response after the
500
+ success POST is a quarantined authorization incident, never a retry signal.
501
+ Neither GitHub Actions nor a process signal handler can make the remote status
502
+ POST, readback, and token revocation atomic. A hard cancellation can therefore
503
+ end the runner before the status-only installation token is revoked; keep both
504
+ writers disabled and begin a fresh 65-minute quarantine from the newest
505
+ authenticated attempt update before any cleanup or writer is admitted.
506
+ Freeze promotion and read the exact target's App-sourced status plus the
507
+ production ref out of band. If the ref did not move, use a separately admitted
508
+ status-only cleanup to append and read back the terminal `error` before starting
509
+ a fresh run from a new baseline. If the ref did move, never move it backward;
510
+ require the exact provider outcome and use only the already-exact recovery path.
511
+ Do not dispatch another writer while the newest exact context is successful or
512
+ unknown.
513
+
514
+ ### Terminalize an interrupted production authority
515
+
516
+ Use `Terminalize release authority` only for a failed `Promote website
517
+ production` attempt whose checked run title durably names the exact immutable
518
+ tag or release target. It is not a general status editor and it cannot clean up
519
+ an unbound historical run. If an older workflow lacks that target-bearing run
520
+ title, keep routine promotion disabled and resolve the target from owner-admin
521
+ evidence; do not treat the cleanup workflow as authority to restart.
522
+
523
+ Before dispatch, disable both `Promote website production` and `Prove
524
+ production ref writer canary`. Freeze workflow dispatches, reruns, Actions run
525
+ history deletion, ruleset administration, App installation changes, and key
526
+ rotation. Record owner-admin readbacks showing both production rulesets have no
527
+ bypass actors and `current_user_can_bypass=never`; the workflow token's rules
528
+ API is intentionally not trusted to prove those administrator-only fields.
529
+ Leave `Terminalize release authority` active, record the three exact workflow
530
+ IDs in `MLM_RELEASE_PRODUCTION_WORKFLOW_ID`,
531
+ `MLM_RELEASE_CANARY_WORKFLOW_ID`, and `MLM_RELEASE_CLEANUP_WORKFLOW_ID`, and
532
+ dispatch attempt 1 with the exact failed production run ID/attempt, immutable
533
+ tag and peeled target SHA, and unchanged production-ref SHA.
534
+
535
+ Treat an Actions run's `name` and `display_title` as presentation fields: a
536
+ workflow-level `run-name` can change them for each invocation. Stable workflow
537
+ identity is the exact numeric workflow ID plus its checked repository path;
538
+ exact run admission additionally binds the repository, run ID, event, attempt,
539
+ and source SHA. Cleanup separately requires the target-bearing `display_title`
540
+ defined by the checked workflow so it cannot select an unrelated failed run,
541
+ but that title is not a substitute for the numeric ID and path.
542
+
543
+ The cleanup inventories every attempt for all three credential-capable
544
+ workflows from one fixed authenticated GitHub `Date` minus 36 days. Thirty-six
545
+ days exceeds GitHub's 35-day maximum workflow lifetime, so a pre-freeze run
546
+ cannot remain runnable outside the inventory. It rejects 1,000 or more retained
547
+ runs for any workflow, more than 51 attempts for one run, more than 150 attempts
548
+ total, a missing attempt, another nonterminal attempt, or any workflow-state
549
+ change. The initial inventory lower bound and freeze anchor are reused
550
+ byte-for-byte through revalidation and postflight. Wait until the authenticated
551
+ completion time is at least 65 minutes after the latest disabled-workflow
552
+ update, inventoried prior-attempt update, and current App predecessor; this
553
+ exceeds the admitted one-hour App-token lifetime. A deleted history item,
554
+ recreated workflow, ambiguous newest failure for the target, changed run title,
555
+ or decreasing inventory digest fails closed. Because an administrator could
556
+ delete and recreate evidence between API reads, the owner freeze and
557
+ before/after admin readbacks remain part of admission.
558
+
559
+ After the main-only environment approval, the helper repeats the complete
560
+ snapshot before it may read the private key. The status-only App may then POST
561
+ only one distinct `error` for the exact failed target, prove that exact status
562
+ through the combined-status endpoint, and revoke the token through the same
563
+ bounded 401-convergence contract as routine promotion. A third complete
564
+ read-only snapshot must bind the exact terminal status, unchanged immutable
565
+ tag/Release and ancestry, unchanged production ref, workflow states, rules and
566
+ inventory. The final verifier then reads the exact terminal status, rules and
567
+ production ref in causal order. Its canonical receipt is written to the job
568
+ summary. If the runner remains available, every final-job bootstrap and
569
+ verification step is guarded with `always()` so an ordinary postflight or final
570
+ verification failure persists a canonical incomplete receipt. The receipt
571
+ retains every available validated initial, revalidated, terminal, and
572
+ postflight object (or its parse-failure digest), plus an independent exact
573
+ production-ref readback when available, and exits nonzero. A hard workflow
574
+ cancellation, runner loss, checkout failure, or platform termination can still
575
+ prevent any finalizer from executing; absence of a receipt is itself an
576
+ indeterminate incident. An incomplete or absent receipt is quarantine evidence,
577
+ never permission to retry.
578
+
579
+ After a complete receipt, repeat the owner-admin no-bypass/ruleset/App/key/run
580
+ inventory readbacks before re-enabling either routine workflow. A cancelled or
581
+ failed cleanup becomes a new externally recorded incident; keep both writers
582
+ disabled and wait a new 65-minute quarantine instead of blindly rerunning it.
583
+ Cleanup never moves or creates a ref, posts `success`, edits a Release, or
584
+ grants restart authority by itself.
585
+
586
+ Any ambiguity, concurrent production deployment, missing or changed baseline
587
+ item, provider error, terminal failure, identity mismatch, ref race, status
588
+ mutation, or timeout fails the promotion closed.
589
+
590
+ Public npm and GitHub artifact admission, including the cryptographic npm
591
+ provenance audit, is repeated before the provider baseline, immediately before
592
+ and after either production-ref path, and before and after the terminal provider
593
+ outcome. A moved npm Latest tag, missing provenance, changed registry integrity,
594
+ changed immutable Release coordinate, or byte mismatch fails the current phase
595
+ closed.
596
+
597
+ ## Recover provider verification
598
+
599
+ Recovery uses the same `Promote website production` workflow dispatch from the
600
+ exact current reviewed `main` workflow source while the separately peeled
601
+ annotated release commit remains in `main` history. Current-main source and
602
+ release bytes are revalidated independently before and after provider work. It
603
+ requires the
604
+ exact existing npm version and immutable artifact-complete Latest Release. It
605
+ never creates, replaces, or edits an npm version or GitHub Release.
606
+
607
+ If `website-production` still precedes the release commit, recovery performs
608
+ the same checked explicit-lease fast-forward only when every newly reachable
609
+ commit preserves the baseline workflow-tree OID, and requires one new provider
610
+ outcome.
611
+ If the ref is already exact, the baseline marks advancement false, skips the
612
+ entire `production-ref-writer-key` job, and mints no App token. A separate
613
+ read-only job accepts only the unique latest exact-SHA Production deployment in
614
+ the stable baseline that postdates the immutable Release. That newest attempt
615
+ itself must be provider-accepted. A newer terminal failure, error, or inactive
616
+ attempt blocks recovery instead of allowing an older success to be reused.
617
+ Recovery then repeats the terminal authority readbacks. A missing ref is a hard
618
+ failure and must not be recreated by the workflow. If the desired transition
619
+ crosses any workflow change, use the separately approved control-epoch
620
+ bootstrap above; after that exact external advancement, the already-exact
621
+ recovery path supplies the provider proof without reading the App key.
622
+
623
+ When a tag run fails after its exact draft or immutable Release exists, preserve
624
+ its evidence and rerun that same workflow. Re-running only failed jobs is
625
+ supported: successful preflight or publisher outputs retain their own actual
626
+ attempt coordinate, while a later writer may only publish still-absent bytes or
627
+ observe exact existing bytes without mutation. The run may safely complete only
628
+ the same tag, commit, deterministic draft, and tarball; npm provenance must bind
629
+ the same run ID and an allowed actual positive attempt. Correct only the failed
630
+ control and use the website recovery path after public admission succeeds. Do
631
+ not retag, delete the immutable Release or exact residual draft, manually move
632
+ `website-production` outside the one separately approved control-epoch
633
+ bootstrap, redeploy from Vercel, or weaken a ruleset to make the run pass.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hraness/message-like-me",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "A local-first CLI and Agent Skill for studying private messaging history and drafting messages that sound like you.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,6 +16,11 @@
16
16
  "bugs": {
17
17
  "url": "https://github.com/hraness/message-like-me/issues"
18
18
  },
19
+ "publishConfig": {
20
+ "access": "public",
21
+ "provenance": true,
22
+ "registry": "https://registry.npmjs.org"
23
+ },
19
24
  "keywords": [
20
25
  "agent-skill",
21
26
  "beeper",
@@ -77,6 +82,7 @@
77
82
  },
78
83
  "devDependencies": {
79
84
  "@types/bun": "1.3.14",
85
+ "sigstore": "4.1.1",
80
86
  "typescript": "6.0.3"
81
87
  }
82
88
  }