approval-md 0.2.0 → 0.4.0
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.
- package/README.md +85 -877
- package/SPEC.md +150 -19
- package/cli.js +66 -7
- package/dist/src/adapters/smtp.d.ts +18 -0
- package/dist/src/adapters/smtp.js +24 -3
- package/dist/src/adapters/smtp.js.map +1 -1
- package/dist/src/channels/contract.d.ts +53 -1
- package/dist/src/channels/contract.js +304 -7
- package/dist/src/channels/contract.js.map +1 -1
- package/dist/src/channels/relay-server.d.ts +90 -0
- package/dist/src/channels/relay-server.js +295 -0
- package/dist/src/channels/relay-server.js.map +1 -0
- package/dist/src/channels/relay.d.ts +273 -0
- package/dist/src/channels/relay.js +564 -0
- package/dist/src/channels/relay.js.map +1 -0
- package/dist/src/channels/tagging.js +6 -1
- package/dist/src/channels/tagging.js.map +1 -1
- package/dist/src/channels/telegram-webhook.d.ts +273 -0
- package/dist/src/channels/telegram-webhook.js +536 -0
- package/dist/src/channels/telegram-webhook.js.map +1 -0
- package/dist/src/channels/telegram.d.ts +394 -12
- package/dist/src/channels/telegram.js +621 -68
- package/dist/src/channels/telegram.js.map +1 -1
- package/dist/src/channels/web.d.ts +9 -0
- package/dist/src/channels/web.js +17 -0
- package/dist/src/channels/web.js.map +1 -1
- package/dist/src/cli/amend.js +564 -34
- package/dist/src/cli/amend.js.map +1 -1
- package/dist/src/cli/attest.d.ts +9 -0
- package/dist/src/cli/attest.js +177 -13
- package/dist/src/cli/attest.js.map +1 -1
- package/dist/src/cli/channel-relay.d.ts +108 -0
- package/dist/src/cli/channel-relay.js +334 -0
- package/dist/src/cli/channel-relay.js.map +1 -0
- package/dist/src/cli/channel-telegram-webhook.d.ts +273 -0
- package/dist/src/cli/channel-telegram-webhook.js +709 -0
- package/dist/src/cli/channel-telegram-webhook.js.map +1 -0
- package/dist/src/cli/channel-telegram.d.ts +347 -28
- package/dist/src/cli/channel-telegram.js +763 -28
- package/dist/src/cli/channel-telegram.js.map +1 -1
- package/dist/src/cli/channel.d.ts +10 -1
- package/dist/src/cli/channel.js +14 -1
- package/dist/src/cli/channel.js.map +1 -1
- package/dist/src/cli/codex-bridge.d.ts +819 -0
- package/dist/src/cli/codex-bridge.js +1607 -0
- package/dist/src/cli/codex-bridge.js.map +1 -0
- package/dist/src/cli/codex.d.ts +1 -1
- package/dist/src/cli/codex.js +304 -7
- package/dist/src/cli/codex.js.map +1 -1
- package/dist/src/cli/daemon.js +41 -6
- package/dist/src/cli/daemon.js.map +1 -1
- package/dist/src/cli/doctor.d.ts +63 -0
- package/dist/src/cli/doctor.js +1322 -122
- package/dist/src/cli/doctor.js.map +1 -1
- package/dist/src/cli/execute.d.ts +17 -1
- package/dist/src/cli/execute.js +366 -22
- package/dist/src/cli/execute.js.map +1 -1
- package/dist/src/cli/exit-codes.d.ts +12 -0
- package/dist/src/cli/exit-codes.js +13 -0
- package/dist/src/cli/exit-codes.js.map +1 -1
- package/dist/src/cli/gate.d.ts +2 -0
- package/dist/src/cli/gate.js +233 -2
- package/dist/src/cli/gate.js.map +1 -1
- package/dist/src/cli/help.d.ts +14 -2
- package/dist/src/cli/help.js +395 -82
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hook-codex.d.ts +49 -1
- package/dist/src/cli/hook-codex.js +60 -1
- package/dist/src/cli/hook-codex.js.map +1 -1
- package/dist/src/cli/hook.d.ts +828 -4
- package/dist/src/cli/hook.js +2972 -142
- package/dist/src/cli/hook.js.map +1 -1
- package/dist/src/cli/import.js +1 -1
- package/dist/src/cli/import.js.map +1 -1
- package/dist/src/cli/init.js +16 -7
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/instructions.js +24 -3
- package/dist/src/cli/instructions.js.map +1 -1
- package/dist/src/cli/log-anchor.d.ts +55 -0
- package/dist/src/cli/log-anchor.js +199 -60
- package/dist/src/cli/log-anchor.js.map +1 -1
- package/dist/src/cli/main.d.ts +0 -12
- package/dist/src/cli/main.js +56 -3
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/muse.d.ts +2 -0
- package/dist/src/cli/muse.js +62 -0
- package/dist/src/cli/muse.js.map +1 -0
- package/dist/src/cli/payload.js +79 -1
- package/dist/src/cli/payload.js.map +1 -1
- package/dist/src/cli/policy-apply.d.ts +195 -0
- package/dist/src/cli/policy-apply.js +573 -0
- package/dist/src/cli/policy-apply.js.map +1 -0
- package/dist/src/cli/policy.js +14 -1
- package/dist/src/cli/policy.js.map +1 -1
- package/dist/src/cli/preflight.d.ts +151 -13
- package/dist/src/cli/preflight.js +398 -41
- package/dist/src/cli/preflight.js.map +1 -1
- package/dist/src/cli/sandbox.js +17 -1
- package/dist/src/cli/sandbox.js.map +1 -1
- package/dist/src/cli/scaffold.d.ts +1 -1
- package/dist/src/cli/scaffold.js +7 -1
- package/dist/src/cli/scaffold.js.map +1 -1
- package/dist/src/cli/serve.d.ts +53 -0
- package/dist/src/cli/serve.js +270 -0
- package/dist/src/cli/serve.js.map +1 -0
- package/dist/src/cli/setup-channel.d.ts +9 -0
- package/dist/src/cli/setup-channel.js +28 -1
- package/dist/src/cli/setup-channel.js.map +1 -1
- package/dist/src/cli/setup-common.d.ts +3 -1
- package/dist/src/cli/setup-common.js +3 -2
- package/dist/src/cli/setup-common.js.map +1 -1
- package/dist/src/cli/setup.d.ts +2 -0
- package/dist/src/cli/setup.js +94 -2
- package/dist/src/cli/setup.js.map +1 -1
- package/dist/src/cli/up.js +134 -51
- package/dist/src/cli/up.js.map +1 -1
- package/dist/src/cli/values.js +3 -4
- package/dist/src/cli/values.js.map +1 -1
- package/dist/src/cli/verb-registry.d.ts +2 -0
- package/dist/src/cli/verb-registry.js +510 -47
- package/dist/src/cli/verb-registry.js.map +1 -1
- package/dist/src/cli/wordmark.d.ts +2 -2
- package/dist/src/cli/wordmark.js +2 -2
- package/dist/src/codex/broker.d.ts +229 -0
- package/dist/src/codex/broker.js +548 -0
- package/dist/src/codex/broker.js.map +1 -0
- package/dist/src/codex/runner.d.ts +178 -0
- package/dist/src/codex/runner.js +231 -0
- package/dist/src/codex/runner.js.map +1 -0
- package/dist/src/codex/serve.d.ts +56 -0
- package/dist/src/codex/serve.js +98 -0
- package/dist/src/codex/serve.js.map +1 -0
- package/dist/src/codex/workspace-commit.d.ts +219 -0
- package/dist/src/codex/workspace-commit.js +549 -0
- package/dist/src/codex/workspace-commit.js.map +1 -0
- package/dist/src/core/advance-cycle.d.ts +51 -0
- package/dist/src/core/advance-cycle.js +66 -2
- package/dist/src/core/advance-cycle.js.map +1 -1
- package/dist/src/core/agents-md.d.ts +20 -18
- package/dist/src/core/agents-md.js +33 -31
- package/dist/src/core/agents-md.js.map +1 -1
- package/dist/src/core/attest-bootstrap.d.ts +95 -0
- package/dist/src/core/attest-bootstrap.js +135 -0
- package/dist/src/core/attest-bootstrap.js.map +1 -0
- package/dist/src/core/attest.d.ts +234 -2
- package/dist/src/core/attest.js +342 -7
- package/dist/src/core/attest.js.map +1 -1
- package/dist/src/core/audit.d.ts +73 -3
- package/dist/src/core/audit.js +65 -5
- package/dist/src/core/audit.js.map +1 -1
- package/dist/src/core/channel-lease.d.ts +322 -0
- package/dist/src/core/channel-lease.js +663 -0
- package/dist/src/core/channel-lease.js.map +1 -0
- package/dist/src/core/channel-owner.d.ts +213 -0
- package/dist/src/core/channel-owner.js +358 -0
- package/dist/src/core/channel-owner.js.map +1 -0
- package/dist/src/core/command-class.d.ts +205 -0
- package/dist/src/core/command-class.js +1433 -28
- package/dist/src/core/command-class.js.map +1 -1
- package/dist/src/core/commit-guard.d.ts +272 -0
- package/dist/src/core/commit-guard.js +424 -0
- package/dist/src/core/commit-guard.js.map +1 -0
- package/dist/src/core/daemon-actor.d.ts +45 -0
- package/dist/src/core/daemon-actor.js +54 -0
- package/dist/src/core/daemon-actor.js.map +1 -0
- package/dist/src/core/daemon-host.d.ts +178 -0
- package/dist/src/core/daemon-host.js +228 -0
- package/dist/src/core/daemon-host.js.map +1 -0
- package/dist/src/core/daemon-identity.d.ts +238 -0
- package/dist/src/core/daemon-identity.js +252 -0
- package/dist/src/core/daemon-identity.js.map +1 -0
- package/dist/src/core/dark-session.d.ts +109 -8
- package/dist/src/core/dark-session.js +266 -82
- package/dist/src/core/dark-session.js.map +1 -1
- package/dist/src/core/decision-refusal.d.ts +23 -2
- package/dist/src/core/decision-refusal.js +24 -2
- package/dist/src/core/decision-refusal.js.map +1 -1
- package/dist/src/core/env-file.d.ts +5 -0
- package/dist/src/core/env-file.js +60 -1
- package/dist/src/core/env-file.js.map +1 -1
- package/dist/src/core/execute.d.ts +15 -2
- package/dist/src/core/execute.js +15 -2
- package/dist/src/core/execute.js.map +1 -1
- package/dist/src/core/gate.d.ts +392 -6
- package/dist/src/core/gate.js +852 -24
- package/dist/src/core/gate.js.map +1 -1
- package/dist/src/core/gesture-refusal.d.ts +166 -0
- package/dist/src/core/gesture-refusal.js +188 -0
- package/dist/src/core/gesture-refusal.js.map +1 -0
- package/dist/src/core/harness-version.d.ts +128 -4
- package/dist/src/core/harness-version.js +181 -12
- package/dist/src/core/harness-version.js.map +1 -1
- package/dist/src/core/harness-wait.d.ts +82 -3
- package/dist/src/core/harness-wait.js +89 -3
- package/dist/src/core/harness-wait.js.map +1 -1
- package/dist/src/core/instance.d.ts +59 -2
- package/dist/src/core/instance.js +113 -0
- package/dist/src/core/instance.js.map +1 -1
- package/dist/src/core/log-subscribe.d.ts +21 -0
- package/dist/src/core/log-subscribe.js +16 -6
- package/dist/src/core/log-subscribe.js.map +1 -1
- package/dist/src/core/log-write-layer.d.ts +55 -0
- package/dist/src/core/log-write-layer.js +91 -0
- package/dist/src/core/log-write-layer.js.map +1 -0
- package/dist/src/core/log.d.ts +89 -22
- package/dist/src/core/log.js +197 -19
- package/dist/src/core/log.js.map +1 -1
- package/dist/src/core/payload-census.d.ts +51 -0
- package/dist/src/core/payload-census.js +125 -2
- package/dist/src/core/payload-census.js.map +1 -1
- package/dist/src/core/payload-store.d.ts +31 -0
- package/dist/src/core/payload-store.js +113 -8
- package/dist/src/core/payload-store.js.map +1 -1
- package/dist/src/core/payload.d.ts +18 -3
- package/dist/src/core/payload.js +20 -4
- package/dist/src/core/payload.js.map +1 -1
- package/dist/src/core/policy-diff.d.ts +10 -0
- package/dist/src/core/policy-diff.js +10 -2
- package/dist/src/core/policy-diff.js.map +1 -1
- package/dist/src/core/policy-explain.d.ts +17 -1
- package/dist/src/core/policy-explain.js +48 -1
- package/dist/src/core/policy-explain.js.map +1 -1
- package/dist/src/core/policy-load.d.ts +65 -1
- package/dist/src/core/policy-load.js +21 -3
- package/dist/src/core/policy-load.js.map +1 -1
- package/dist/src/core/policy-match.d.ts +81 -0
- package/dist/src/core/policy-match.js +87 -0
- package/dist/src/core/policy-match.js.map +1 -1
- package/dist/src/core/policy-proposal.d.ts +75 -0
- package/dist/src/core/policy-proposal.js +110 -4
- package/dist/src/core/policy-proposal.js.map +1 -1
- package/dist/src/core/protected-path-guard.d.ts +117 -4
- package/dist/src/core/protected-path-guard.js +362 -48
- package/dist/src/core/protected-path-guard.js.map +1 -1
- package/dist/src/core/question-preempted.d.ts +141 -0
- package/dist/src/core/question-preempted.js +152 -0
- package/dist/src/core/question-preempted.js.map +1 -0
- package/dist/src/core/read-scope.d.ts +182 -0
- package/dist/src/core/read-scope.js +256 -0
- package/dist/src/core/read-scope.js.map +1 -0
- package/dist/src/core/run-payload.d.ts +160 -0
- package/dist/src/core/run-payload.js +304 -0
- package/dist/src/core/run-payload.js.map +1 -0
- package/dist/src/core/sandbox.d.ts +81 -0
- package/dist/src/core/sandbox.js +190 -1
- package/dist/src/core/sandbox.js.map +1 -1
- package/dist/src/core/sender-identity.d.ts +501 -0
- package/dist/src/core/sender-identity.js +609 -0
- package/dist/src/core/sender-identity.js.map +1 -0
- package/dist/src/core/shlex.d.ts +102 -0
- package/dist/src/core/shlex.js +159 -0
- package/dist/src/core/shlex.js.map +1 -0
- package/dist/src/core/state.d.ts +52 -1
- package/dist/src/core/state.js +52 -6
- package/dist/src/core/state.js.map +1 -1
- package/dist/src/core/telegram-config.d.ts +79 -0
- package/dist/src/core/telegram-config.js +108 -0
- package/dist/src/core/telegram-config.js.map +1 -1
- package/dist/src/core/values.d.ts +18 -8
- package/dist/src/core/values.js +36 -1
- package/dist/src/core/values.js.map +1 -1
- package/dist/src/core/verify.d.ts +23 -1
- package/dist/src/core/verify.js +20 -2
- package/dist/src/core/verify.js.map +1 -1
- package/dist/src/daemon/advance.d.ts +10 -0
- package/dist/src/daemon/advance.js +25 -4
- package/dist/src/daemon/advance.js.map +1 -1
- package/dist/src/daemon/audit.d.ts +80 -5
- package/dist/src/daemon/audit.js +126 -6
- package/dist/src/daemon/audit.js.map +1 -1
- package/dist/src/daemon/daemon.d.ts +174 -2
- package/dist/src/daemon/daemon.js +307 -7
- package/dist/src/daemon/daemon.js.map +1 -1
- package/dist/src/daemon/git-evidence.d.ts +2 -2
- package/dist/src/daemon/git-evidence.js +1 -1
- package/dist/src/daemon/projection.d.ts +13 -2
- package/dist/src/daemon/projection.js +39 -6
- package/dist/src/daemon/projection.js.map +1 -1
- package/dist/src/mcp/server.d.ts +39 -3
- package/dist/src/mcp/server.js +30 -3
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/muse/server.d.ts +16 -0
- package/dist/src/muse/server.js +238 -0
- package/dist/src/muse/server.js.map +1 -0
- package/dist/src/serve/archive.d.ts +158 -0
- package/dist/src/serve/archive.js +354 -0
- package/dist/src/serve/archive.js.map +1 -0
- package/dist/src/serve/arguments.d.ts +93 -0
- package/dist/src/serve/arguments.js +228 -0
- package/dist/src/serve/arguments.js.map +1 -0
- package/dist/src/serve/credentials.d.ts +91 -0
- package/dist/src/serve/credentials.js +143 -0
- package/dist/src/serve/credentials.js.map +1 -0
- package/dist/src/serve/follow.d.ts +86 -0
- package/dist/src/serve/follow.js +101 -0
- package/dist/src/serve/follow.js.map +1 -0
- package/dist/src/serve/hook-thread.d.ts +134 -0
- package/dist/src/serve/hook-thread.js +333 -0
- package/dist/src/serve/hook-thread.js.map +1 -0
- package/dist/src/serve/hook-worker.d.ts +134 -0
- package/dist/src/serve/hook-worker.js +173 -0
- package/dist/src/serve/hook-worker.js.map +1 -0
- package/dist/src/serve/server.d.ts +412 -0
- package/dist/src/serve/server.js +1251 -0
- package/dist/src/serve/server.js.map +1 -0
- package/docs/README-extended.md +766 -0
- package/docs/cli-reference.md +2563 -73
- package/docs/codex-enforced-session.md +75 -2
- package/docs/codex-workspace-broker.md +118 -0
- package/package.json +6 -2
- package/schema/event.schema.json +595 -9
- package/schema/fixtures/event/invalid/approval-granted-sender-hashed-false.json +20 -0
- package/schema/fixtures/event/invalid/approval-granted-sender-hashed-raw-id.json +20 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-human-actor.json +16 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-no-actor-no-sender.json +15 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-unknown-gesture.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-agent-actor.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-no-question-id.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-unknown-source.json +15 -0
- package/schema/fixtures/event/invalid/daemon-id-malformed.json +15 -0
- package/schema/fixtures/event/invalid/execution-started-truncated-policy-sha256.json +18 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-absolute-path.json +14 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-agent-actor.json +14 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-missing-path.json +13 -0
- package/schema/fixtures/event/invalid/harness-cap-at-margin.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-fractional.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-negative.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-string.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-without-harness-execution.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-zero.json +16 -0
- package/schema/fixtures/event/valid/approval-granted-sender-hashed.json +20 -0
- package/schema/fixtures/event/valid/approval-requested-harness-cap.json +18 -0
- package/schema/fixtures/event/valid/audit-gesture-refused-review-note.json +21 -0
- package/schema/fixtures/event/valid/audit-gesture-refused-sender-key-unavailable.json +19 -0
- package/schema/fixtures/event/valid/audit-gesture-refused.json +19 -0
- package/schema/fixtures/event/valid/audit-question-preempted-no-verdict.json +16 -0
- package/schema/fixtures/event/valid/audit-question-preempted.json +20 -0
- package/schema/fixtures/event/valid/daemon-identity-declared.json +17 -0
- package/schema/fixtures/event/valid/daemon-identity.json +15 -0
- package/schema/fixtures/event/valid/execution-started-policy-sha256.json +18 -0
- package/schema/fixtures/event/valid/gate-path-signed-off.json +14 -0
- package/schema/fixtures/event/valid/harness-kind-claude-code.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-codex.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-cursor.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-grok.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-hermes.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-muse.json +23 -0
- package/schema/fixtures/policy/invalid/daemons-malformed-id.json +10 -0
- package/schema/fixtures/policy/invalid/senders-half-keyed.json +20 -0
- package/schema/fixtures/policy/valid/canonical.json +1 -1
- package/schema/fixtures/policy/valid/daemons-allowlist.json +19 -0
- package/schema/fixtures/policy/valid/senders-keyed.json +24 -0
- package/schema/fixtures/policy-md/invalid/schema-invalid-agent-may-request.md +21 -0
- package/schema/fixtures/policy-md/valid/agent-may-request.md +24 -0
- package/schema/fixtures/policy-md/valid/canonical.md +1 -1
- package/schema/fixtures/policy-md/valid/with-values.md +5 -7
- package/schema/fixtures/values/invalid/class-shaped.json +1 -1
- package/schema/fixtures/values/invalid/duplicate-entry.json +1 -1
- package/schema/fixtures/values/invalid/non-string-item.json +1 -1
- package/schema/fixtures/values/invalid/over-cap.json +1 -1
- package/schema/fixtures/values/invalid/unknown-key.json +1 -1
- package/schema/fixtures/values/invalid/version-float.json +1 -0
- package/schema/fixtures/values/invalid/version-integer.json +1 -0
- package/schema/fixtures/values/invalid/version-wrong-string.json +1 -0
- package/schema/fixtures/values/valid/empty-lists.json +2 -3
- package/schema/fixtures/values/valid/full.json +5 -7
- package/schema/fixtures/values/valid/minimal.json +1 -1
- package/schema/fixtures/values-md/invalid/schema-invalid.md +5 -3
- package/schema/fixtures/values-md/invalid/two-blocks.md +3 -3
- package/schema/fixtures/values-md/invalid/unterminated.md +2 -2
- package/schema/fixtures/values-md/invalid/version-1.md +69 -0
- package/schema/fixtures/values-md/invalid/version-unquoted.md +64 -0
- package/schema/fixtures/values-md/invalid/yaml-error.md +2 -2
- package/schema/fixtures/values-md/valid/absent.md +1 -1
- package/schema/fixtures/values-md/valid/with-values.md +5 -7
- package/schema/policy.schema.json +100 -4
- package/schema/values.schema.json +7 -11
- package/schema/fixtures/values/invalid/version-string.json +0 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the log says when a decision surface refused a gesture that is not a
|
|
3
|
+
* decision (APRV-355, amended SPEC.md §8).
|
|
4
|
+
*
|
|
5
|
+
* ## The fact this module is about
|
|
6
|
+
*
|
|
7
|
+
* Found while landing APRV-324 (PR #427, 2026-09-17). Once the policy maps
|
|
8
|
+
* Telegram senders, a tap on a CHECKPOINT signature or on a REVIEW from an
|
|
9
|
+
* account the attested policy names nobody for is refused before any verb runs
|
|
10
|
+
* — and records nothing. The only refusal record in the system is
|
|
11
|
+
* `audit.decision_refused`, and it requires a record-level `action_key` and a
|
|
12
|
+
* `payload.decision` of grant, reject or revoke. A signature answers for a
|
|
13
|
+
* chain head and a review answers for a sampled record; neither has either
|
|
14
|
+
* field, so writing one of these there would mean manufacturing both. The lane
|
|
15
|
+
* that found it declined to, correctly.
|
|
16
|
+
*
|
|
17
|
+
* The cost of recording nothing is the same cost `core/decision-refusal.ts`
|
|
18
|
+
* exists to end. Somebody's attention was spent — SPEC.md §11 calls human
|
|
19
|
+
* attention the audit budget — and an attempt was made from an account the
|
|
20
|
+
* operator did not map, and the only trace is a line on a terminal and an
|
|
21
|
+
* answer in a chat. An operator deciding whether to map that account has
|
|
22
|
+
* nothing in the log to read.
|
|
23
|
+
*
|
|
24
|
+
* ## What this record is, and what it is not
|
|
25
|
+
*
|
|
26
|
+
* `audit.gesture_refused` is an AUDIT-TIER record on the strict terms
|
|
27
|
+
* `audit.decision_refused` set, and the terms are the whole of its safety:
|
|
28
|
+
*
|
|
29
|
+
* - it grants nothing and mints no token;
|
|
30
|
+
* - `core/state.ts` settles nothing on it, so no verdict moves;
|
|
31
|
+
* - `core/budgets.ts` charges nothing for it, so no budget moves;
|
|
32
|
+
* - `core/audit.ts` does not sample it and no streak counts it;
|
|
33
|
+
* - NO ENFORCEMENT PATH READS IT. `tests/gesture-refusal.test.ts` pins that by
|
|
34
|
+
* reading the module graph rather than by asserting an intention.
|
|
35
|
+
*
|
|
36
|
+
* The record's own actor is `system:`, for the reason `audit.dark_session`'s
|
|
37
|
+
* and `audit.decision_refused`'s are: this is the runtime's statement about a
|
|
38
|
+
* refusal the runtime made, and a record of a refusal authored by either party
|
|
39
|
+
* to it is a record neither party can be held to. The person, when the runtime
|
|
40
|
+
* can name one, is the SUBJECT and sits in the payload.
|
|
41
|
+
*
|
|
42
|
+
* ## The asymmetry it inherits
|
|
43
|
+
*
|
|
44
|
+
* Refusals handed to AGENTS stay unlogged here too. An agent that is refused
|
|
45
|
+
* reads the code, stops or asks again, and nothing was spent that a record
|
|
46
|
+
* could account for. And a gesture is human by construction: an agent has no
|
|
47
|
+
* checkpoint to sign and no review to give.
|
|
48
|
+
*
|
|
49
|
+
* ## No attestation check, deliberately
|
|
50
|
+
*
|
|
51
|
+
* Nothing here asks whether the policy is attested, for the reason
|
|
52
|
+
* `core/decision-refusal.ts` does not: this write confers no authority.
|
|
53
|
+
* Refusing to record a refusal because a file changed would be the strict
|
|
54
|
+
* direction pointing the wrong way, and the case where it would bite hardest is
|
|
55
|
+
* `policy-not-attested` itself — exactly the refusal an operator most needs the
|
|
56
|
+
* log to remember. The write boundary still validates every record.
|
|
57
|
+
*
|
|
58
|
+
* ## Invariants
|
|
59
|
+
*
|
|
60
|
+
* - **Gate-typed events never accept caller timestamps** (§11.1). `ts` comes
|
|
61
|
+
* from the injected clock at the write boundary; there is no parameter.
|
|
62
|
+
* - **Every check-then-append passes through compare-and-append** (§11.1(5)).
|
|
63
|
+
* The write states the head it was derived against and the whole cycle
|
|
64
|
+
* re-enters from a fresh read on `head-moved` through {@link withHeadRetry}.
|
|
65
|
+
* - **Self-reported fields never reduce scrutiny** (§11.1). Everything here
|
|
66
|
+
* only ADDS to what a reviewer sees. The sender is the transport's own
|
|
67
|
+
* attribution, never anything the message claimed about itself.
|
|
68
|
+
* - **Refusals stay machine-readable and distinct** (§11.1). The surface's code
|
|
69
|
+
* is copied verbatim; nothing here invents, merges or softens one.
|
|
70
|
+
*/
|
|
71
|
+
import { tick } from "./clock.js";
|
|
72
|
+
import { attemptsOf, withHeadRetry } from "./head-retry.js";
|
|
73
|
+
import { appendEvent } from "./log.js";
|
|
74
|
+
import { readVerifiedRecords } from "./state.js";
|
|
75
|
+
/** The actor every record here carries: the gate stating what the gate did. */
|
|
76
|
+
export const GESTURE_REFUSAL_ACTOR = "system:gate";
|
|
77
|
+
/**
|
|
78
|
+
* The gestures this record can be about. **Closed and additive-only** (§11.1
|
|
79
|
+
* invariant 6), and pinned against the event schema's own enum by
|
|
80
|
+
* `tests/gesture-refusal.test.ts`: a kind the sweep can produce and the write
|
|
81
|
+
* boundary refuses is an observation that never reaches a human, which is the
|
|
82
|
+
* failure APRV-358 named a few hours before this task.
|
|
83
|
+
*
|
|
84
|
+
* `review` and `review-note` are two members rather than one because a note is
|
|
85
|
+
* attention spent WRITING rather than attention spent tapping, and an operator
|
|
86
|
+
* reading this record to decide whether to map an account wants to know which
|
|
87
|
+
* they lost.
|
|
88
|
+
*/
|
|
89
|
+
export const REFUSED_GESTURES = ["checkpoint-signature", "review", "review-note"];
|
|
90
|
+
/**
|
|
91
|
+
* The refusals a gesture can meet before any verb runs. **Closed**, and exactly
|
|
92
|
+
* what sender resolution can answer: `sender-unmapped`, `sender-ambiguous` and
|
|
93
|
+
* `sender-key-unavailable` from `core/sender-identity.ts`'s own union, and
|
|
94
|
+
* `policy-not-attested` from `core/attest.ts`, which fires when the policy
|
|
95
|
+
* declaring the mapping is not the attested one and is therefore not in force.
|
|
96
|
+
*
|
|
97
|
+
* `attest-requires-terminal` is deliberately absent: it belongs to an
|
|
98
|
+
* attestation tap, which is a decision and is recorded as one.
|
|
99
|
+
*/
|
|
100
|
+
export const REFUSED_GESTURE_CODES = [
|
|
101
|
+
"sender-unmapped",
|
|
102
|
+
"sender-ambiguous",
|
|
103
|
+
// APRV-370. A keyed mapping this process holds no key for: the runtime could
|
|
104
|
+
// resolve no account at all, which is a different fact from "this account is
|
|
105
|
+
// not mapped" and wants a different repair.
|
|
106
|
+
"sender-key-unavailable",
|
|
107
|
+
"policy-not-attested",
|
|
108
|
+
];
|
|
109
|
+
/** Is `code` one this record can carry? Used where a code arrives as a string. */
|
|
110
|
+
export function isRefusedGestureCode(code) {
|
|
111
|
+
return REFUSED_GESTURE_CODES.includes(code);
|
|
112
|
+
}
|
|
113
|
+
/** The gestures this module records: a person's, and nobody else's. */
|
|
114
|
+
const HUMAN_ACTOR = /^human:.+/u;
|
|
115
|
+
/**
|
|
116
|
+
* Record that a human's gesture was refused.
|
|
117
|
+
*
|
|
118
|
+
* Called by the surface that collected the gesture, on the branch where it
|
|
119
|
+
* refused — never from inside the verb the gesture would have reached, which is
|
|
120
|
+
* never called at all on this path.
|
|
121
|
+
*
|
|
122
|
+
* Best-effort by design: a failure here is returned, never thrown, and the
|
|
123
|
+
* caller shows the refusal either way. The gesture was already refused before
|
|
124
|
+
* this ran, and nothing about that outcome depends on this write landing.
|
|
125
|
+
*
|
|
126
|
+
* Two cases append nothing, and both are the honest answer rather than a
|
|
127
|
+
* silence:
|
|
128
|
+
*
|
|
129
|
+
* - a non-human actor, which is the misconfigured-surface case: nobody's
|
|
130
|
+
* attention was spent, so there is no spend for a record to account for;
|
|
131
|
+
* - a code this record cannot carry, which means a surface refused for a reason
|
|
132
|
+
* this vocabulary does not name. Minting a member here to fit it would widen
|
|
133
|
+
* a closed union at the write boundary from inside a best-effort path.
|
|
134
|
+
*/
|
|
135
|
+
export function recordRefusedGesture(logPath, gesture, refusal, options = {}) {
|
|
136
|
+
if (gesture.actor !== null && !HUMAN_ACTOR.test(gesture.actor)) {
|
|
137
|
+
return { ok: true, audit: null };
|
|
138
|
+
}
|
|
139
|
+
// No person and no account is nothing to say: the record would name neither
|
|
140
|
+
// the subject nor the reason it could not, and the schema refuses it.
|
|
141
|
+
if (gesture.actor === null && gesture.sender === undefined) {
|
|
142
|
+
return { ok: true, audit: null };
|
|
143
|
+
}
|
|
144
|
+
if (!isRefusedGestureCode(refusal.code))
|
|
145
|
+
return { ok: true, audit: null };
|
|
146
|
+
const appended = withHeadRetry(attemptsOf(options.retryOnHeadMoved), () => appendAudit(logPath, gesture, refusal, options));
|
|
147
|
+
return appended.ok ? { ok: true, audit: appended.record } : appended;
|
|
148
|
+
}
|
|
149
|
+
/** The whole cycle: a fresh read for the head, then one append against it. */
|
|
150
|
+
function appendAudit(logPath, gesture, refusal, options) {
|
|
151
|
+
const ts = tick(options);
|
|
152
|
+
const read = readVerifiedRecords(logPath, options.schemaDir === undefined ? {} : { schemaDir: options.schemaDir });
|
|
153
|
+
if (!read.ok) {
|
|
154
|
+
return { ok: false, code: "log-unreadable", message: read.message };
|
|
155
|
+
}
|
|
156
|
+
const payload = {
|
|
157
|
+
...(gesture.actor === null ? {} : { actor: gesture.actor }),
|
|
158
|
+
gesture: gesture.gesture,
|
|
159
|
+
code: refusal.code,
|
|
160
|
+
message: refusal.message,
|
|
161
|
+
};
|
|
162
|
+
if (gesture.sender !== undefined) {
|
|
163
|
+
payload["sender"] = {
|
|
164
|
+
channel: gesture.sender.channel,
|
|
165
|
+
id: gesture.sender.id,
|
|
166
|
+
// APRV-370: only when true, so a raw record does not change shape.
|
|
167
|
+
...(gesture.sender.hashed === true ? { hashed: true } : {}),
|
|
168
|
+
};
|
|
169
|
+
if (gesture.senderSource !== undefined)
|
|
170
|
+
payload["sender_source"] = gesture.senderSource;
|
|
171
|
+
}
|
|
172
|
+
return appendOne(logPath, { ts, actor: GESTURE_REFUSAL_ACTOR, channel: gesture.channel, payload }, options, read.head);
|
|
173
|
+
}
|
|
174
|
+
function appendOne(logPath, input, options, expectedHead) {
|
|
175
|
+
const append = { ...options.append };
|
|
176
|
+
if (options.schemaDir !== undefined)
|
|
177
|
+
append.schemaDir = options.schemaDir;
|
|
178
|
+
const result = appendEvent(logPath, { ...input, event: "audit.gesture_refused" }, { ...append, expectedHead });
|
|
179
|
+
if (result.ok)
|
|
180
|
+
return { ok: true, record: result.record };
|
|
181
|
+
return {
|
|
182
|
+
ok: false,
|
|
183
|
+
code: "append-failed",
|
|
184
|
+
message: `audit.gesture_refused could not be appended: ${result.error.message}`,
|
|
185
|
+
append: result.error,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=gesture-refusal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gesture-refusal.js","sourceRoot":"","sources":["../../../src/core/gesture-refusal.ts"],"names":[],"mappings":"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"}
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
* only seam, and a test puts a stub binary in front of it.
|
|
53
53
|
*/
|
|
54
54
|
/** The harnesses this runtime speaks a hook protocol for. */
|
|
55
|
-
export declare const HARNESS_KINDS: readonly ["claude-code", "cursor", "codex"];
|
|
55
|
+
export declare const HARNESS_KINDS: readonly ["claude-code", "cursor", "codex", "grok", "muse", "hermes"];
|
|
56
56
|
export type HarnessKind = (typeof HARNESS_KINDS)[number];
|
|
57
57
|
/** Is `value` one of the harnesses this runtime knows? */
|
|
58
58
|
export declare function isHarnessKind(value: unknown): value is HarnessKind;
|
|
@@ -102,7 +102,30 @@ export declare function normalizeHarnessVersion(raw: unknown): string | null;
|
|
|
102
102
|
*/
|
|
103
103
|
export declare const HARNESS_PROBE_TIMEOUT_MS = 10000;
|
|
104
104
|
/**
|
|
105
|
-
*
|
|
105
|
+
* How long the RAW first line of `<binary> --version` may be.
|
|
106
|
+
*
|
|
107
|
+
* Wider than {@link HARNESS_VERSION_LIMIT} because it holds a different kind of
|
|
108
|
+
* value for a different reader: nothing capped by this number is ever appended to
|
|
109
|
+
* the log (only {@link normalizeHarnessVersion}'s output is), and what needs the
|
|
110
|
+
* raw line is a diagnostic that must be able to read a build stamp a harness
|
|
111
|
+
* prints beside its semver. Hermes prints
|
|
112
|
+
* `Hermes Agent v0.21.3 (2026.9.14) · upstream 913d4098`, which the log's own
|
|
113
|
+
* rule rejects on the non-ASCII separator alone. Capped and stripped of control
|
|
114
|
+
* characters all the same: this is third-party output on its way to a terminal.
|
|
115
|
+
*/
|
|
116
|
+
export declare const HARNESS_RAW_VERSION_LIMIT = 200;
|
|
117
|
+
/**
|
|
118
|
+
* The first line of a `--version` output, as a line a diagnostic may print.
|
|
119
|
+
*
|
|
120
|
+
* One line, trimmed, control characters removed, capped. `null` for empty output
|
|
121
|
+
* or a line past the cap. It keeps non-ASCII bytes, which is the whole difference
|
|
122
|
+
* from {@link normalizeHarnessVersion}: a build stamp behind a typographic
|
|
123
|
+
* separator is exactly the fact a version floor has to read, and it is exactly
|
|
124
|
+
* the fact the write boundary will not accept.
|
|
125
|
+
*/
|
|
126
|
+
export declare function rawHarnessVersionLine(raw: unknown): string | null;
|
|
127
|
+
/**
|
|
128
|
+
* Run `<binary> --version` once, uncached, and return its raw first line.
|
|
106
129
|
*
|
|
107
130
|
* Every failure is a value rather than an exception, in the manner of
|
|
108
131
|
* {@link spawnGloss}: a missing binary, a non-zero exit and a timeout kill are
|
|
@@ -113,16 +136,117 @@ export declare const HARNESS_PROBE_TIMEOUT_MS = 10000;
|
|
|
113
136
|
* vault passphrase, and it has no use for either. Nothing is declared, because
|
|
114
137
|
* reading a version is not a granted action.
|
|
115
138
|
*/
|
|
139
|
+
export declare function probeHarnessVersionRaw(kind: HarnessKind): string | null;
|
|
140
|
+
/**
|
|
141
|
+
* Run `<binary> --version` once, uncached, and normalize what came back.
|
|
142
|
+
*
|
|
143
|
+
* The recordable form: one line, printable ASCII, capped. Exported for the test
|
|
144
|
+
* that proves the memo below is a memo.
|
|
145
|
+
*/
|
|
116
146
|
export declare function probeHarnessVersion(kind: HarnessKind): string | null;
|
|
147
|
+
/** The raw first line of `<binary> --version`, read at most once per process. */
|
|
148
|
+
export declare function installedHarnessVersionRaw(kind: HarnessKind): string | null;
|
|
117
149
|
/**
|
|
118
150
|
* The installed version of `kind`, read at most once per process.
|
|
119
151
|
*
|
|
120
|
-
* This is the only entry point callers should use
|
|
121
|
-
* exported for the test that proves the memo is a memo.
|
|
152
|
+
* This is the only entry point callers should use for a RECORDABLE version.
|
|
153
|
+
* `probeHarnessVersion` is exported for the test that proves the memo is a memo.
|
|
122
154
|
*/
|
|
123
155
|
export declare function installedHarnessVersion(kind: HarnessKind): string | null;
|
|
124
156
|
/** Drop the memo. TEST ONLY: a process reads a version once, by design. */
|
|
125
157
|
export declare function resetHarnessVersionCache(): void;
|
|
158
|
+
/**
|
|
159
|
+
* The build at which Hermes Agent starts honouring `fail_closed` (APRV-415).
|
|
160
|
+
*
|
|
161
|
+
* ## Why a floor exists at all, and why it is a DATE rather than a version
|
|
162
|
+
*
|
|
163
|
+
* `approval hook hermes` is enforcement rather than a backstop only because of a
|
|
164
|
+
* per-entry `fail_closed: true` that makes a hook crash, a hook timeout and
|
|
165
|
+
* unparseable hook output BLOCK. The live probe measured both halves of that on
|
|
166
|
+
* two builds of the same harness, and the answer differs between them:
|
|
167
|
+
*
|
|
168
|
+
* - `main` at `118984d7`, built 2026-09-20: crash, garbage and hang were all
|
|
169
|
+
* REFUSED (the hang at the 300s per-entry cap). The key works;
|
|
170
|
+
* - `v0.21.3`, built 2026.9.14: all three PROCEEDED. That build does not know the
|
|
171
|
+
* key and ignores it SILENTLY. `hermes hooks list` renders no `fail_closed`
|
|
172
|
+
* flag on either build, so the listing cannot be used to tell them apart.
|
|
173
|
+
*
|
|
174
|
+
* The two builds report the SAME semver. `hermes --version` on the older one
|
|
175
|
+
* prints `Hermes Agent v0.21.3 (2026.9.14) · upstream 913d4098`, and the update
|
|
176
|
+
* that fixed the behaviour moved 670 commits without moving `0.21.3`. So a floor
|
|
177
|
+
* expressed as a semantic version would compare the one field that did not
|
|
178
|
+
* change, and would pass a build that fails open. The build DATE and the upstream
|
|
179
|
+
* commit are the two fields that did move, and they are what this compares.
|
|
180
|
+
*
|
|
181
|
+
* ## What it can and cannot do
|
|
182
|
+
*
|
|
183
|
+
* It can only ADD a red line to `approval doctor` (SPEC.md §11.1 invariant 4: a
|
|
184
|
+
* self-reported field never reduces scrutiny). A build claiming a later date buys
|
|
185
|
+
* nothing — it defeats a row that would have asked a human to look — and nothing
|
|
186
|
+
* in the runtime reads this to widen a verdict, skip a wait or lower a class. The
|
|
187
|
+
* refusals the adapter emits are the same on every build; what changes below the
|
|
188
|
+
* floor is whether a BROKEN hook stops the call, which no code in this repository
|
|
189
|
+
* can observe from inside the hook it is broken in.
|
|
190
|
+
*/
|
|
191
|
+
export declare const HERMES_FAIL_CLOSED_FLOOR: {
|
|
192
|
+
/** The first build observed to honour the key, by upstream commit. */
|
|
193
|
+
readonly upstream: "118984d7";
|
|
194
|
+
/** That build's date, in the `YYYY.M.D` stamp `hermes --version` prints. */
|
|
195
|
+
readonly date: {
|
|
196
|
+
readonly year: 2026;
|
|
197
|
+
readonly month: 9;
|
|
198
|
+
readonly day: 20;
|
|
199
|
+
};
|
|
200
|
+
/** The one sentence every surface quotes, so they cannot drift apart. */
|
|
201
|
+
readonly statement: "a build at or after main 118984d7 of 2026-09-20; v0.21.3 (2026.9.14) fails open silently";
|
|
202
|
+
};
|
|
203
|
+
/** A build stamp, as `hermes --version` prints one. */
|
|
204
|
+
export interface HermesBuildDate {
|
|
205
|
+
year: number;
|
|
206
|
+
month: number;
|
|
207
|
+
day: number;
|
|
208
|
+
}
|
|
209
|
+
/** What `hermes --version`'s first line states, field by field. */
|
|
210
|
+
export interface HermesVersionFields {
|
|
211
|
+
/** The semver, which did NOT move across the fail-closed fix. */
|
|
212
|
+
semver: string | null;
|
|
213
|
+
/** The build date, `(2026.9.14)`, which did. */
|
|
214
|
+
date: HermesBuildDate | null;
|
|
215
|
+
/** The upstream commit, `· upstream 913d4098`, which did. */
|
|
216
|
+
upstream: string | null;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Read the fields out of `hermes --version`'s first line, or `null`.
|
|
220
|
+
*
|
|
221
|
+
* Shape-only and forgiving in one direction: a field this cannot find is `null`
|
|
222
|
+
* rather than a guess, and a line naming none of the three is not a Hermes
|
|
223
|
+
* version line at all. The observed line is
|
|
224
|
+
* `Hermes Agent v0.21.3 (2026.9.14) · upstream 913d4098`; the separator is read
|
|
225
|
+
* past rather than required, because a release that changes its punctuation must
|
|
226
|
+
* not silently turn the floor check into an unknown.
|
|
227
|
+
*/
|
|
228
|
+
export declare function parseHermesVersion(raw: unknown): HermesVersionFields | null;
|
|
229
|
+
/**
|
|
230
|
+
* Does this Hermes build honour `fail_closed`?
|
|
231
|
+
*
|
|
232
|
+
* - `"honours"` — its upstream commit IS the floor's, or its build date is on or
|
|
233
|
+
* after the floor's date;
|
|
234
|
+
* - `"ignores"` — its build date is BEFORE the floor's. This is the one answer
|
|
235
|
+
* that names a fault, and it is the state a live probe measured rather than
|
|
236
|
+
* inferred;
|
|
237
|
+
* - `"unknown"` — no version could be read, or the line carries neither a build
|
|
238
|
+
* date nor the floor's commit. Two commit hashes cannot be ORDERED without a
|
|
239
|
+
* repository, so a build stamped with an unfamiliar commit and no date is
|
|
240
|
+
* honestly unknown rather than quietly either.
|
|
241
|
+
*
|
|
242
|
+
* `"unknown"` is not a synonym for `"ignores"`, deliberately. This value feeds a
|
|
243
|
+
* health check, and a health check that cried fault on every unreadable banner
|
|
244
|
+
* would train an operator to stop reading it, which costs more than the case it
|
|
245
|
+
* would catch. What guards the unknown case instead is the doc, the help block
|
|
246
|
+
* and the probe's own report, all of which state {@link
|
|
247
|
+
* HERMES_FAIL_CLOSED_FLOOR.statement} verbatim.
|
|
248
|
+
*/
|
|
249
|
+
export declare function hermesFailClosedSupport(raw: unknown): "honours" | "ignores" | "unknown";
|
|
126
250
|
/**
|
|
127
251
|
* The provenance pair a hook-written record carries, or `null` when this
|
|
128
252
|
* process could not establish one.
|
|
@@ -54,7 +54,14 @@
|
|
|
54
54
|
import { spawnSync } from "node:child_process";
|
|
55
55
|
import { childEnvironment } from "./child-env.js";
|
|
56
56
|
/** The harnesses this runtime speaks a hook protocol for. */
|
|
57
|
-
export const HARNESS_KINDS = [
|
|
57
|
+
export const HARNESS_KINDS = [
|
|
58
|
+
"claude-code",
|
|
59
|
+
"cursor",
|
|
60
|
+
"codex",
|
|
61
|
+
"grok",
|
|
62
|
+
"muse",
|
|
63
|
+
"hermes",
|
|
64
|
+
];
|
|
58
65
|
/** Is `value` one of the harnesses this runtime knows? */
|
|
59
66
|
export function isHarnessKind(value) {
|
|
60
67
|
return typeof value === "string" && HARNESS_KINDS.includes(value);
|
|
@@ -69,6 +76,9 @@ export const HARNESS_BINARY = {
|
|
|
69
76
|
"claude-code": "claude",
|
|
70
77
|
cursor: "cursor-agent",
|
|
71
78
|
codex: "codex",
|
|
79
|
+
grok: "grok",
|
|
80
|
+
muse: "muse",
|
|
81
|
+
hermes: "hermes",
|
|
72
82
|
};
|
|
73
83
|
/**
|
|
74
84
|
* How long a version string may be, and the reason there is a cap at all.
|
|
@@ -119,7 +129,40 @@ export function normalizeHarnessVersion(raw) {
|
|
|
119
129
|
*/
|
|
120
130
|
export const HARNESS_PROBE_TIMEOUT_MS = 10_000;
|
|
121
131
|
/**
|
|
122
|
-
*
|
|
132
|
+
* How long the RAW first line of `<binary> --version` may be.
|
|
133
|
+
*
|
|
134
|
+
* Wider than {@link HARNESS_VERSION_LIMIT} because it holds a different kind of
|
|
135
|
+
* value for a different reader: nothing capped by this number is ever appended to
|
|
136
|
+
* the log (only {@link normalizeHarnessVersion}'s output is), and what needs the
|
|
137
|
+
* raw line is a diagnostic that must be able to read a build stamp a harness
|
|
138
|
+
* prints beside its semver. Hermes prints
|
|
139
|
+
* `Hermes Agent v0.21.3 (2026.9.14) · upstream 913d4098`, which the log's own
|
|
140
|
+
* rule rejects on the non-ASCII separator alone. Capped and stripped of control
|
|
141
|
+
* characters all the same: this is third-party output on its way to a terminal.
|
|
142
|
+
*/
|
|
143
|
+
export const HARNESS_RAW_VERSION_LIMIT = 200;
|
|
144
|
+
/**
|
|
145
|
+
* The first line of a `--version` output, as a line a diagnostic may print.
|
|
146
|
+
*
|
|
147
|
+
* One line, trimmed, control characters removed, capped. `null` for empty output
|
|
148
|
+
* or a line past the cap. It keeps non-ASCII bytes, which is the whole difference
|
|
149
|
+
* from {@link normalizeHarnessVersion}: a build stamp behind a typographic
|
|
150
|
+
* separator is exactly the fact a version floor has to read, and it is exactly
|
|
151
|
+
* the fact the write boundary will not accept.
|
|
152
|
+
*/
|
|
153
|
+
export function rawHarnessVersionLine(raw) {
|
|
154
|
+
if (typeof raw !== "string")
|
|
155
|
+
return null;
|
|
156
|
+
const first = raw.split("\n", 1)[0] ?? "";
|
|
157
|
+
// `\p{Cc}` rather than an escaped range: the class is the Unicode CONTROL
|
|
158
|
+
// category, which is the thing being removed, and it reads as that.
|
|
159
|
+
const text = first.replace(/\p{Cc}/gu, "").trim();
|
|
160
|
+
if (text.length === 0 || text.length > HARNESS_RAW_VERSION_LIMIT)
|
|
161
|
+
return null;
|
|
162
|
+
return text;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Run `<binary> --version` once, uncached, and return its raw first line.
|
|
123
166
|
*
|
|
124
167
|
* Every failure is a value rather than an exception, in the manner of
|
|
125
168
|
* {@link spawnGloss}: a missing binary, a non-zero exit and a timeout kill are
|
|
@@ -130,7 +173,7 @@ export const HARNESS_PROBE_TIMEOUT_MS = 10_000;
|
|
|
130
173
|
* vault passphrase, and it has no use for either. Nothing is declared, because
|
|
131
174
|
* reading a version is not a granted action.
|
|
132
175
|
*/
|
|
133
|
-
export function
|
|
176
|
+
export function probeHarnessVersionRaw(kind) {
|
|
134
177
|
let result;
|
|
135
178
|
try {
|
|
136
179
|
result = spawnSync(HARNESS_BINARY[kind], ["--version"], {
|
|
@@ -148,32 +191,158 @@ export function probeHarnessVersion(kind) {
|
|
|
148
191
|
}
|
|
149
192
|
if (result.error !== undefined || result.status !== 0)
|
|
150
193
|
return null;
|
|
151
|
-
return
|
|
194
|
+
return rawHarnessVersionLine(result.stdout);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Run `<binary> --version` once, uncached, and normalize what came back.
|
|
198
|
+
*
|
|
199
|
+
* The recordable form: one line, printable ASCII, capped. Exported for the test
|
|
200
|
+
* that proves the memo below is a memo.
|
|
201
|
+
*/
|
|
202
|
+
export function probeHarnessVersion(kind) {
|
|
203
|
+
return normalizeHarnessVersion(probeHarnessVersionRaw(kind));
|
|
152
204
|
}
|
|
153
205
|
/**
|
|
154
206
|
* The memo. Holds the FAILURES too: a harness that is not on PATH is not on
|
|
155
207
|
* PATH, and asking a second time in the same process would pay a second spawn
|
|
156
208
|
* for the same `null`.
|
|
157
|
-
*/
|
|
158
|
-
const probed = new Map();
|
|
159
|
-
/**
|
|
160
|
-
* The installed version of `kind`, read at most once per process.
|
|
161
209
|
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
210
|
+
* It holds the RAW line rather than the recordable one, so the two readers — the
|
|
211
|
+
* provenance field and the version floor — still cost ONE spawn per process
|
|
212
|
+
* between them. A harness whose raw line the write boundary rejects has a
|
|
213
|
+
* `null` recordable version and a readable raw one, which is precisely Hermes's
|
|
214
|
+
* case and precisely why the floor is not read off a record.
|
|
164
215
|
*/
|
|
165
|
-
|
|
216
|
+
const probed = new Map();
|
|
217
|
+
/** The raw first line of `<binary> --version`, read at most once per process. */
|
|
218
|
+
export function installedHarnessVersionRaw(kind) {
|
|
166
219
|
const memo = probed.get(kind);
|
|
167
220
|
if (memo !== undefined)
|
|
168
221
|
return memo;
|
|
169
|
-
const value =
|
|
222
|
+
const value = probeHarnessVersionRaw(kind);
|
|
170
223
|
probed.set(kind, value);
|
|
171
224
|
return value;
|
|
172
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* The installed version of `kind`, read at most once per process.
|
|
228
|
+
*
|
|
229
|
+
* This is the only entry point callers should use for a RECORDABLE version.
|
|
230
|
+
* `probeHarnessVersion` is exported for the test that proves the memo is a memo.
|
|
231
|
+
*/
|
|
232
|
+
export function installedHarnessVersion(kind) {
|
|
233
|
+
return normalizeHarnessVersion(installedHarnessVersionRaw(kind));
|
|
234
|
+
}
|
|
173
235
|
/** Drop the memo. TEST ONLY: a process reads a version once, by design. */
|
|
174
236
|
export function resetHarnessVersionCache() {
|
|
175
237
|
probed.clear();
|
|
176
238
|
}
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// The Hermes fail-closed version floor (APRV-415)
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
/**
|
|
243
|
+
* The build at which Hermes Agent starts honouring `fail_closed` (APRV-415).
|
|
244
|
+
*
|
|
245
|
+
* ## Why a floor exists at all, and why it is a DATE rather than a version
|
|
246
|
+
*
|
|
247
|
+
* `approval hook hermes` is enforcement rather than a backstop only because of a
|
|
248
|
+
* per-entry `fail_closed: true` that makes a hook crash, a hook timeout and
|
|
249
|
+
* unparseable hook output BLOCK. The live probe measured both halves of that on
|
|
250
|
+
* two builds of the same harness, and the answer differs between them:
|
|
251
|
+
*
|
|
252
|
+
* - `main` at `118984d7`, built 2026-09-20: crash, garbage and hang were all
|
|
253
|
+
* REFUSED (the hang at the 300s per-entry cap). The key works;
|
|
254
|
+
* - `v0.21.3`, built 2026.9.14: all three PROCEEDED. That build does not know the
|
|
255
|
+
* key and ignores it SILENTLY. `hermes hooks list` renders no `fail_closed`
|
|
256
|
+
* flag on either build, so the listing cannot be used to tell them apart.
|
|
257
|
+
*
|
|
258
|
+
* The two builds report the SAME semver. `hermes --version` on the older one
|
|
259
|
+
* prints `Hermes Agent v0.21.3 (2026.9.14) · upstream 913d4098`, and the update
|
|
260
|
+
* that fixed the behaviour moved 670 commits without moving `0.21.3`. So a floor
|
|
261
|
+
* expressed as a semantic version would compare the one field that did not
|
|
262
|
+
* change, and would pass a build that fails open. The build DATE and the upstream
|
|
263
|
+
* commit are the two fields that did move, and they are what this compares.
|
|
264
|
+
*
|
|
265
|
+
* ## What it can and cannot do
|
|
266
|
+
*
|
|
267
|
+
* It can only ADD a red line to `approval doctor` (SPEC.md §11.1 invariant 4: a
|
|
268
|
+
* self-reported field never reduces scrutiny). A build claiming a later date buys
|
|
269
|
+
* nothing — it defeats a row that would have asked a human to look — and nothing
|
|
270
|
+
* in the runtime reads this to widen a verdict, skip a wait or lower a class. The
|
|
271
|
+
* refusals the adapter emits are the same on every build; what changes below the
|
|
272
|
+
* floor is whether a BROKEN hook stops the call, which no code in this repository
|
|
273
|
+
* can observe from inside the hook it is broken in.
|
|
274
|
+
*/
|
|
275
|
+
export const HERMES_FAIL_CLOSED_FLOOR = {
|
|
276
|
+
/** The first build observed to honour the key, by upstream commit. */
|
|
277
|
+
upstream: "118984d7",
|
|
278
|
+
/** That build's date, in the `YYYY.M.D` stamp `hermes --version` prints. */
|
|
279
|
+
date: { year: 2026, month: 9, day: 20 },
|
|
280
|
+
/** The one sentence every surface quotes, so they cannot drift apart. */
|
|
281
|
+
statement: "a build at or after main 118984d7 of 2026-09-20; v0.21.3 (2026.9.14) fails open silently",
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Read the fields out of `hermes --version`'s first line, or `null`.
|
|
285
|
+
*
|
|
286
|
+
* Shape-only and forgiving in one direction: a field this cannot find is `null`
|
|
287
|
+
* rather than a guess, and a line naming none of the three is not a Hermes
|
|
288
|
+
* version line at all. The observed line is
|
|
289
|
+
* `Hermes Agent v0.21.3 (2026.9.14) · upstream 913d4098`; the separator is read
|
|
290
|
+
* past rather than required, because a release that changes its punctuation must
|
|
291
|
+
* not silently turn the floor check into an unknown.
|
|
292
|
+
*/
|
|
293
|
+
export function parseHermesVersion(raw) {
|
|
294
|
+
const line = rawHarnessVersionLine(raw);
|
|
295
|
+
if (line === null)
|
|
296
|
+
return null;
|
|
297
|
+
const semver = /\bv(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)\b/u.exec(line);
|
|
298
|
+
const stamp = /\((\d{4})\.(\d{1,2})\.(\d{1,2})\)/u.exec(line);
|
|
299
|
+
const upstream = /\bupstream\s+([0-9a-f]{7,40})\b/iu.exec(line);
|
|
300
|
+
if (semver === null && stamp === null && upstream === null)
|
|
301
|
+
return null;
|
|
302
|
+
return {
|
|
303
|
+
semver: semver?.[1] ?? null,
|
|
304
|
+
date: stamp === null
|
|
305
|
+
? null
|
|
306
|
+
: {
|
|
307
|
+
year: Number(stamp[1]),
|
|
308
|
+
month: Number(stamp[2]),
|
|
309
|
+
day: Number(stamp[3]),
|
|
310
|
+
},
|
|
311
|
+
upstream: upstream?.[1]?.toLowerCase() ?? null,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Does this Hermes build honour `fail_closed`?
|
|
316
|
+
*
|
|
317
|
+
* - `"honours"` — its upstream commit IS the floor's, or its build date is on or
|
|
318
|
+
* after the floor's date;
|
|
319
|
+
* - `"ignores"` — its build date is BEFORE the floor's. This is the one answer
|
|
320
|
+
* that names a fault, and it is the state a live probe measured rather than
|
|
321
|
+
* inferred;
|
|
322
|
+
* - `"unknown"` — no version could be read, or the line carries neither a build
|
|
323
|
+
* date nor the floor's commit. Two commit hashes cannot be ORDERED without a
|
|
324
|
+
* repository, so a build stamped with an unfamiliar commit and no date is
|
|
325
|
+
* honestly unknown rather than quietly either.
|
|
326
|
+
*
|
|
327
|
+
* `"unknown"` is not a synonym for `"ignores"`, deliberately. This value feeds a
|
|
328
|
+
* health check, and a health check that cried fault on every unreadable banner
|
|
329
|
+
* would train an operator to stop reading it, which costs more than the case it
|
|
330
|
+
* would catch. What guards the unknown case instead is the doc, the help block
|
|
331
|
+
* and the probe's own report, all of which state {@link
|
|
332
|
+
* HERMES_FAIL_CLOSED_FLOOR.statement} verbatim.
|
|
333
|
+
*/
|
|
334
|
+
export function hermesFailClosedSupport(raw) {
|
|
335
|
+
const fields = parseHermesVersion(raw);
|
|
336
|
+
if (fields === null)
|
|
337
|
+
return "unknown";
|
|
338
|
+
const floor = HERMES_FAIL_CLOSED_FLOOR;
|
|
339
|
+
if (fields.upstream !== null && fields.upstream.startsWith(floor.upstream))
|
|
340
|
+
return "honours";
|
|
341
|
+
if (fields.date === null)
|
|
342
|
+
return "unknown";
|
|
343
|
+
const asNumber = (date) => date.year * 10_000 + date.month * 100 + date.day;
|
|
344
|
+
return asNumber(fields.date) >= asNumber(floor.date) ? "honours" : "ignores";
|
|
345
|
+
}
|
|
177
346
|
/**
|
|
178
347
|
* Build the pair for `kind`, preferring the version the hook event supplied.
|
|
179
348
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness-version.js","sourceRoot":"","sources":["../../../src/core/harness-version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,
|
|
1
|
+
{"version":3,"file":"harness-version.js","sourceRoot":"","sources":["../../../src/core/harness-version.ts"],"names":[],"mappings":"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"}
|