approval-md 0.0.1 → 0.2.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/LICENSE +176 -0
- package/NOTICE +5 -0
- package/README.md +940 -4
- package/SPEC.md +476 -34
- package/cli.js +29 -3
- package/dist/src/adapters/agentmail.d.ts +426 -0
- package/dist/src/adapters/agentmail.js +1200 -0
- package/dist/src/adapters/agentmail.js.map +1 -0
- package/dist/src/adapters/conformance.d.ts +149 -0
- package/dist/src/adapters/conformance.js +461 -0
- package/dist/src/adapters/conformance.js.map +1 -0
- package/dist/src/adapters/contract.d.ts +628 -0
- package/dist/src/adapters/contract.js +1035 -0
- package/dist/src/adapters/contract.js.map +1 -0
- package/dist/src/adapters/email.d.ts +324 -0
- package/dist/src/adapters/email.js +749 -0
- package/dist/src/adapters/email.js.map +1 -0
- package/dist/src/adapters/env-passphrase.d.ts +93 -0
- package/dist/src/adapters/env-passphrase.js +132 -0
- package/dist/src/adapters/env-passphrase.js.map +1 -0
- package/dist/src/adapters/public.d.ts +11 -0
- package/dist/src/adapters/public.js +11 -0
- package/dist/src/adapters/public.js.map +1 -0
- package/dist/src/adapters/registry.d.ts +59 -0
- package/dist/src/adapters/registry.js +77 -0
- package/dist/src/adapters/registry.js.map +1 -0
- package/dist/src/adapters/smtp.d.ts +213 -0
- package/dist/src/adapters/smtp.js +499 -0
- package/dist/src/adapters/smtp.js.map +1 -0
- package/dist/src/adapters/vault-provider.d.ts +114 -0
- package/dist/src/adapters/vault-provider.js +161 -0
- package/dist/src/adapters/vault-provider.js.map +1 -0
- package/dist/src/adapters/zzz.d.ts +66 -0
- package/dist/src/adapters/zzz.js +299 -0
- package/dist/src/adapters/zzz.js.map +1 -0
- package/dist/src/channels/batch.d.ts +109 -0
- package/dist/src/channels/batch.js +121 -0
- package/dist/src/channels/batch.js.map +1 -0
- package/dist/src/channels/cli.d.ts +193 -0
- package/dist/src/channels/cli.js +468 -0
- package/dist/src/channels/cli.js.map +1 -0
- package/dist/src/channels/conformance.d.ts +92 -0
- package/dist/src/channels/conformance.js +445 -0
- package/dist/src/channels/conformance.js.map +1 -0
- package/dist/src/channels/contract.d.ts +623 -0
- package/dist/src/channels/contract.js +494 -0
- package/dist/src/channels/contract.js.map +1 -0
- package/dist/src/channels/payload-view.d.ts +35 -0
- package/dist/src/channels/payload-view.js +43 -0
- package/dist/src/channels/payload-view.js.map +1 -0
- package/dist/src/channels/render-queue.d.ts +149 -0
- package/dist/src/channels/render-queue.js +564 -0
- package/dist/src/channels/render-queue.js.map +1 -0
- package/dist/src/channels/tagging.d.ts +196 -0
- package/dist/src/channels/tagging.js +723 -0
- package/dist/src/channels/tagging.js.map +1 -0
- package/dist/src/channels/telegram.d.ts +1832 -0
- package/dist/src/channels/telegram.js +3190 -0
- package/dist/src/channels/telegram.js.map +1 -0
- package/dist/src/channels/web.d.ts +341 -0
- package/dist/src/channels/web.js +903 -0
- package/dist/src/channels/web.js.map +1 -0
- package/dist/src/cli/adapter.d.ts +90 -0
- package/dist/src/cli/adapter.js +288 -0
- package/dist/src/cli/adapter.js.map +1 -0
- package/dist/src/cli/amend.d.ts +59 -0
- package/dist/src/cli/amend.js +2171 -0
- package/dist/src/cli/amend.js.map +1 -0
- package/dist/src/cli/args.d.ts +43 -0
- package/dist/src/cli/args.js +86 -0
- package/dist/src/cli/args.js.map +1 -0
- package/dist/src/cli/attest.d.ts +41 -0
- package/dist/src/cli/attest.js +307 -0
- package/dist/src/cli/attest.js.map +1 -0
- package/dist/src/cli/audit-card.d.ts +62 -0
- package/dist/src/cli/audit-card.js +201 -0
- package/dist/src/cli/audit-card.js.map +1 -0
- package/dist/src/cli/audit.d.ts +59 -0
- package/dist/src/cli/audit.js +460 -0
- package/dist/src/cli/audit.js.map +1 -0
- package/dist/src/cli/channel-telegram.d.ts +806 -0
- package/dist/src/cli/channel-telegram.js +2063 -0
- package/dist/src/cli/channel-telegram.js.map +1 -0
- package/dist/src/cli/channel-web.d.ts +131 -0
- package/dist/src/cli/channel-web.js +357 -0
- package/dist/src/cli/channel-web.js.map +1 -0
- package/dist/src/cli/channel.d.ts +71 -0
- package/dist/src/cli/channel.js +438 -0
- package/dist/src/cli/channel.js.map +1 -0
- package/dist/src/cli/checkpoint-tap.d.ts +169 -0
- package/dist/src/cli/checkpoint-tap.js +238 -0
- package/dist/src/cli/checkpoint-tap.js.map +1 -0
- package/dist/src/cli/codex.d.ts +2 -0
- package/dist/src/cli/codex.js +172 -0
- package/dist/src/cli/codex.js.map +1 -0
- package/dist/src/cli/coverage.d.ts +61 -0
- package/dist/src/cli/coverage.js +343 -0
- package/dist/src/cli/coverage.js.map +1 -0
- package/dist/src/cli/daemon.d.ts +120 -0
- package/dist/src/cli/daemon.js +631 -0
- package/dist/src/cli/daemon.js.map +1 -0
- package/dist/src/cli/doctor.d.ts +129 -0
- package/dist/src/cli/doctor.js +2762 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/env.d.ts +65 -0
- package/dist/src/cli/env.js +302 -0
- package/dist/src/cli/env.js.map +1 -0
- package/dist/src/cli/execute.d.ts +202 -0
- package/dist/src/cli/execute.js +1682 -0
- package/dist/src/cli/execute.js.map +1 -0
- package/dist/src/cli/exit-codes.d.ts +73 -0
- package/dist/src/cli/exit-codes.js +82 -0
- package/dist/src/cli/exit-codes.js.map +1 -0
- package/dist/src/cli/feedback.d.ts +60 -0
- package/dist/src/cli/feedback.js +205 -0
- package/dist/src/cli/feedback.js.map +1 -0
- package/dist/src/cli/gate-window.d.ts +40 -0
- package/dist/src/cli/gate-window.js +294 -0
- package/dist/src/cli/gate-window.js.map +1 -0
- package/dist/src/cli/gate.d.ts +68 -0
- package/dist/src/cli/gate.js +557 -0
- package/dist/src/cli/gate.js.map +1 -0
- package/dist/src/cli/git-scope.d.ts +190 -0
- package/dist/src/cli/git-scope.js +295 -0
- package/dist/src/cli/git-scope.js.map +1 -0
- package/dist/src/cli/gloss-attach.d.ts +85 -0
- package/dist/src/cli/gloss-attach.js +107 -0
- package/dist/src/cli/gloss-attach.js.map +1 -0
- package/dist/src/cli/gloss-codex-child.d.ts +9 -0
- package/dist/src/cli/gloss-codex-child.js +149 -0
- package/dist/src/cli/gloss-codex-child.js.map +1 -0
- package/dist/src/cli/gloss-codex.d.ts +24 -0
- package/dist/src/cli/gloss-codex.js +255 -0
- package/dist/src/cli/gloss-codex.js.map +1 -0
- package/dist/src/cli/gloss-options.d.ts +42 -0
- package/dist/src/cli/gloss-options.js +79 -0
- package/dist/src/cli/gloss-options.js.map +1 -0
- package/dist/src/cli/gloss.d.ts +265 -0
- package/dist/src/cli/gloss.js +362 -0
- package/dist/src/cli/gloss.js.map +1 -0
- package/dist/src/cli/help.d.ts +103 -0
- package/dist/src/cli/help.js +2339 -0
- package/dist/src/cli/help.js.map +1 -0
- package/dist/src/cli/hook-codex.d.ts +78 -0
- package/dist/src/cli/hook-codex.js +167 -0
- package/dist/src/cli/hook-codex.js.map +1 -0
- package/dist/src/cli/hook.d.ts +331 -0
- package/dist/src/cli/hook.js +2849 -0
- package/dist/src/cli/hook.js.map +1 -0
- package/dist/src/cli/import.d.ts +35 -0
- package/dist/src/cli/import.js +175 -0
- package/dist/src/cli/import.js.map +1 -0
- package/dist/src/cli/init.d.ts +84 -0
- package/dist/src/cli/init.js +336 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/instructions.d.ts +23 -0
- package/dist/src/cli/instructions.js +262 -0
- package/dist/src/cli/instructions.js.map +1 -0
- package/dist/src/cli/journal.d.ts +41 -0
- package/dist/src/cli/journal.js +238 -0
- package/dist/src/cli/journal.js.map +1 -0
- package/dist/src/cli/log-advance.d.ts +287 -0
- package/dist/src/cli/log-advance.js +840 -0
- package/dist/src/cli/log-advance.js.map +1 -0
- package/dist/src/cli/log-anchor.d.ts +176 -0
- package/dist/src/cli/log-anchor.js +387 -0
- package/dist/src/cli/log-anchor.js.map +1 -0
- package/dist/src/cli/log-checkpoint.d.ts +22 -0
- package/dist/src/cli/log-checkpoint.js +128 -0
- package/dist/src/cli/log-checkpoint.js.map +1 -0
- package/dist/src/cli/log-sync.d.ts +243 -0
- package/dist/src/cli/log-sync.js +849 -0
- package/dist/src/cli/log-sync.js.map +1 -0
- package/dist/src/cli/log-verbs.d.ts +16 -0
- package/dist/src/cli/log-verbs.js +360 -0
- package/dist/src/cli/log-verbs.js.map +1 -0
- package/dist/src/cli/long-help.d.ts +70 -0
- package/dist/src/cli/long-help.js +148 -0
- package/dist/src/cli/long-help.js.map +1 -0
- package/dist/src/cli/main.d.ts +77 -0
- package/dist/src/cli/main.js +1206 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/mcp.d.ts +52 -0
- package/dist/src/cli/mcp.js +306 -0
- package/dist/src/cli/mcp.js.map +1 -0
- package/dist/src/cli/paths.d.ts +56 -0
- package/dist/src/cli/paths.js +79 -0
- package/dist/src/cli/paths.js.map +1 -0
- package/dist/src/cli/payload.d.ts +58 -0
- package/dist/src/cli/payload.js +253 -0
- package/dist/src/cli/payload.js.map +1 -0
- package/dist/src/cli/policy.d.ts +43 -0
- package/dist/src/cli/policy.js +229 -0
- package/dist/src/cli/policy.js.map +1 -0
- package/dist/src/cli/preflight.d.ts +363 -0
- package/dist/src/cli/preflight.js +1175 -0
- package/dist/src/cli/preflight.js.map +1 -0
- package/dist/src/cli/progress.d.ts +78 -0
- package/dist/src/cli/progress.js +112 -0
- package/dist/src/cli/progress.js.map +1 -0
- package/dist/src/cli/prompt.d.ts +209 -0
- package/dist/src/cli/prompt.js +312 -0
- package/dist/src/cli/prompt.js.map +1 -0
- package/dist/src/cli/quickstart.d.ts +46 -0
- package/dist/src/cli/quickstart.js +297 -0
- package/dist/src/cli/quickstart.js.map +1 -0
- package/dist/src/cli/records.d.ts +34 -0
- package/dist/src/cli/records.js +66 -0
- package/dist/src/cli/records.js.map +1 -0
- package/dist/src/cli/render.d.ts +22 -0
- package/dist/src/cli/render.js +132 -0
- package/dist/src/cli/render.js.map +1 -0
- package/dist/src/cli/sandbox.d.ts +51 -0
- package/dist/src/cli/sandbox.js +150 -0
- package/dist/src/cli/sandbox.js.map +1 -0
- package/dist/src/cli/scaffold.d.ts +79 -0
- package/dist/src/cli/scaffold.js +137 -0
- package/dist/src/cli/scaffold.js.map +1 -0
- package/dist/src/cli/setup-adapter.d.ts +137 -0
- package/dist/src/cli/setup-adapter.js +509 -0
- package/dist/src/cli/setup-adapter.js.map +1 -0
- package/dist/src/cli/setup-channel.d.ts +117 -0
- package/dist/src/cli/setup-channel.js +635 -0
- package/dist/src/cli/setup-channel.js.map +1 -0
- package/dist/src/cli/setup-checkpoint.d.ts +57 -0
- package/dist/src/cli/setup-checkpoint.js +196 -0
- package/dist/src/cli/setup-checkpoint.js.map +1 -0
- package/dist/src/cli/setup-common.d.ts +275 -0
- package/dist/src/cli/setup-common.js +376 -0
- package/dist/src/cli/setup-common.js.map +1 -0
- package/dist/src/cli/setup-flow.d.ts +287 -0
- package/dist/src/cli/setup-flow.js +476 -0
- package/dist/src/cli/setup-flow.js.map +1 -0
- package/dist/src/cli/setup-service.d.ts +96 -0
- package/dist/src/cli/setup-service.js +308 -0
- package/dist/src/cli/setup-service.js.map +1 -0
- package/dist/src/cli/setup.d.ts +202 -0
- package/dist/src/cli/setup.js +473 -0
- package/dist/src/cli/setup.js.map +1 -0
- package/dist/src/cli/style.d.ts +320 -0
- package/dist/src/cli/style.js +469 -0
- package/dist/src/cli/style.js.map +1 -0
- package/dist/src/cli/token.d.ts +39 -0
- package/dist/src/cli/token.js +274 -0
- package/dist/src/cli/token.js.map +1 -0
- package/dist/src/cli/up.d.ts +155 -0
- package/dist/src/cli/up.js +849 -0
- package/dist/src/cli/up.js.map +1 -0
- package/dist/src/cli/usage.d.ts +37 -0
- package/dist/src/cli/usage.js +91 -0
- package/dist/src/cli/usage.js.map +1 -0
- package/dist/src/cli/values.d.ts +40 -0
- package/dist/src/cli/values.js +189 -0
- package/dist/src/cli/values.js.map +1 -0
- package/dist/src/cli/vault.d.ts +59 -0
- package/dist/src/cli/vault.js +362 -0
- package/dist/src/cli/vault.js.map +1 -0
- package/dist/src/cli/verb-registry.d.ts +76 -0
- package/dist/src/cli/verb-registry.js +2341 -0
- package/dist/src/cli/verb-registry.js.map +1 -0
- package/dist/src/cli/wordmark.d.ts +31 -0
- package/dist/src/cli/wordmark.js +52 -0
- package/dist/src/cli/wordmark.js.map +1 -0
- package/dist/src/codex/doctor.d.ts +13 -0
- package/dist/src/codex/doctor.js +41 -0
- package/dist/src/codex/doctor.js.map +1 -0
- package/dist/src/codex/manifest.d.ts +49 -0
- package/dist/src/codex/manifest.js +103 -0
- package/dist/src/codex/manifest.js.map +1 -0
- package/dist/src/codex/templates.d.ts +41 -0
- package/dist/src/codex/templates.js +319 -0
- package/dist/src/codex/templates.js.map +1 -0
- package/dist/src/codex/trust.d.ts +19 -0
- package/dist/src/codex/trust.js +183 -0
- package/dist/src/codex/trust.js.map +1 -0
- package/dist/src/codex/workspace-plan.d.ts +131 -0
- package/dist/src/codex/workspace-plan.js +561 -0
- package/dist/src/codex/workspace-plan.js.map +1 -0
- package/dist/src/core/actor.d.ts +2 -0
- package/dist/src/core/actor.js +5 -0
- package/dist/src/core/actor.js.map +1 -0
- package/dist/src/core/advance-cycle.d.ts +170 -0
- package/dist/src/core/advance-cycle.js +200 -0
- package/dist/src/core/advance-cycle.js.map +1 -0
- package/dist/src/core/agents-md.d.ts +276 -0
- package/dist/src/core/agents-md.js +747 -0
- package/dist/src/core/agents-md.js.map +1 -0
- package/dist/src/core/apply-patch.d.ts +49 -0
- package/dist/src/core/apply-patch.js +266 -0
- package/dist/src/core/apply-patch.js.map +1 -0
- package/dist/src/core/attest.d.ts +420 -0
- package/dist/src/core/attest.js +589 -0
- package/dist/src/core/attest.js.map +1 -0
- package/dist/src/core/audit.d.ts +492 -0
- package/dist/src/core/audit.js +882 -0
- package/dist/src/core/audit.js.map +1 -0
- package/dist/src/core/budgets.d.ts +238 -0
- package/dist/src/core/budgets.js +449 -0
- package/dist/src/core/budgets.js.map +1 -0
- package/dist/src/core/checkpoint.d.ts +500 -0
- package/dist/src/core/checkpoint.js +738 -0
- package/dist/src/core/checkpoint.js.map +1 -0
- package/dist/src/core/child-env.d.ts +88 -0
- package/dist/src/core/child-env.js +86 -0
- package/dist/src/core/child-env.js.map +1 -0
- package/dist/src/core/clock.d.ts +52 -0
- package/dist/src/core/clock.js +43 -0
- package/dist/src/core/clock.js.map +1 -0
- package/dist/src/core/command-class.d.ts +543 -0
- package/dist/src/core/command-class.js +2356 -0
- package/dist/src/core/command-class.js.map +1 -0
- package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
- package/dist/src/core/coverage-sources/adapter.js +71 -0
- package/dist/src/core/coverage-sources/adapter.js.map +1 -0
- package/dist/src/core/coverage-sources/gh.d.ts +48 -0
- package/dist/src/core/coverage-sources/gh.js +136 -0
- package/dist/src/core/coverage-sources/gh.js.map +1 -0
- package/dist/src/core/coverage-sources/git.d.ts +101 -0
- package/dist/src/core/coverage-sources/git.js +269 -0
- package/dist/src/core/coverage-sources/git.js.map +1 -0
- package/dist/src/core/coverage.d.ts +217 -0
- package/dist/src/core/coverage.js +337 -0
- package/dist/src/core/coverage.js.map +1 -0
- package/dist/src/core/credential-spec.d.ts +72 -0
- package/dist/src/core/credential-spec.js +23 -0
- package/dist/src/core/credential-spec.js.map +1 -0
- package/dist/src/core/dark-session.d.ts +331 -0
- package/dist/src/core/dark-session.js +714 -0
- package/dist/src/core/dark-session.js.map +1 -0
- package/dist/src/core/decision-refusal.d.ts +185 -0
- package/dist/src/core/decision-refusal.js +265 -0
- package/dist/src/core/decision-refusal.js.map +1 -0
- package/dist/src/core/env-file.d.ts +450 -0
- package/dist/src/core/env-file.js +837 -0
- package/dist/src/core/env-file.js.map +1 -0
- package/dist/src/core/execute.d.ts +858 -0
- package/dist/src/core/execute.js +1271 -0
- package/dist/src/core/execute.js.map +1 -0
- package/dist/src/core/frontmatter.d.ts +78 -0
- package/dist/src/core/frontmatter.js +100 -0
- package/dist/src/core/frontmatter.js.map +1 -0
- package/dist/src/core/gate-window.d.ts +312 -0
- package/dist/src/core/gate-window.js +506 -0
- package/dist/src/core/gate-window.js.map +1 -0
- package/dist/src/core/gate.d.ts +1364 -0
- package/dist/src/core/gate.js +3002 -0
- package/dist/src/core/gate.js.map +1 -0
- package/dist/src/core/git-run.d.ts +73 -0
- package/dist/src/core/git-run.js +93 -0
- package/dist/src/core/git-run.js.map +1 -0
- package/dist/src/core/harness-version.d.ts +157 -0
- package/dist/src/core/harness-version.js +211 -0
- package/dist/src/core/harness-version.js.map +1 -0
- package/dist/src/core/harness-wait.d.ts +55 -0
- package/dist/src/core/harness-wait.js +58 -0
- package/dist/src/core/harness-wait.js.map +1 -0
- package/dist/src/core/head-retry.d.ts +107 -0
- package/dist/src/core/head-retry.js +121 -0
- package/dist/src/core/head-retry.js.map +1 -0
- package/dist/src/core/instance.d.ts +253 -0
- package/dist/src/core/instance.js +319 -0
- package/dist/src/core/instance.js.map +1 -0
- package/dist/src/core/intake-limits.d.ts +247 -0
- package/dist/src/core/intake-limits.js +350 -0
- package/dist/src/core/intake-limits.js.map +1 -0
- package/dist/src/core/jcs.d.ts +52 -0
- package/dist/src/core/jcs.js +132 -0
- package/dist/src/core/jcs.js.map +1 -0
- package/dist/src/core/journal.d.ts +144 -0
- package/dist/src/core/journal.js +200 -0
- package/dist/src/core/journal.js.map +1 -0
- package/dist/src/core/live-draw.d.ts +436 -0
- package/dist/src/core/live-draw.js +703 -0
- package/dist/src/core/live-draw.js.map +1 -0
- package/dist/src/core/log-reconcile.d.ts +89 -0
- package/dist/src/core/log-reconcile.js +136 -0
- package/dist/src/core/log-reconcile.js.map +1 -0
- package/dist/src/core/log-subscribe.d.ts +36 -0
- package/dist/src/core/log-subscribe.js +162 -0
- package/dist/src/core/log-subscribe.js.map +1 -0
- package/dist/src/core/log.d.ts +278 -0
- package/dist/src/core/log.js +546 -0
- package/dist/src/core/log.js.map +1 -0
- package/dist/src/core/loop.d.ts +274 -0
- package/dist/src/core/loop.js +487 -0
- package/dist/src/core/loop.js.map +1 -0
- package/dist/src/core/md-fence.d.ts +41 -0
- package/dist/src/core/md-fence.js +74 -0
- package/dist/src/core/md-fence.js.map +1 -0
- package/dist/src/core/money.d.ts +147 -0
- package/dist/src/core/money.js +195 -0
- package/dist/src/core/money.js.map +1 -0
- package/dist/src/core/payload-census.d.ts +74 -0
- package/dist/src/core/payload-census.js +146 -0
- package/dist/src/core/payload-census.js.map +1 -0
- package/dist/src/core/payload-store.d.ts +175 -0
- package/dist/src/core/payload-store.js +340 -0
- package/dist/src/core/payload-store.js.map +1 -0
- package/dist/src/core/payload.d.ts +71 -0
- package/dist/src/core/payload.js +80 -0
- package/dist/src/core/payload.js.map +1 -0
- package/dist/src/core/policy-diff.d.ts +292 -0
- package/dist/src/core/policy-diff.js +588 -0
- package/dist/src/core/policy-diff.js.map +1 -0
- package/dist/src/core/policy-expectations.d.ts +199 -0
- package/dist/src/core/policy-expectations.js +394 -0
- package/dist/src/core/policy-expectations.js.map +1 -0
- package/dist/src/core/policy-explain.d.ts +150 -0
- package/dist/src/core/policy-explain.js +258 -0
- package/dist/src/core/policy-explain.js.map +1 -0
- package/dist/src/core/policy-load.d.ts +527 -0
- package/dist/src/core/policy-load.js +536 -0
- package/dist/src/core/policy-load.js.map +1 -0
- package/dist/src/core/policy-match.d.ts +281 -0
- package/dist/src/core/policy-match.js +478 -0
- package/dist/src/core/policy-match.js.map +1 -0
- package/dist/src/core/policy-proposal.d.ts +265 -0
- package/dist/src/core/policy-proposal.js +458 -0
- package/dist/src/core/policy-proposal.js.map +1 -0
- package/dist/src/core/prompt-layout.d.ts +221 -0
- package/dist/src/core/prompt-layout.js +422 -0
- package/dist/src/core/prompt-layout.js.map +1 -0
- package/dist/src/core/protected-path-guard.d.ts +453 -0
- package/dist/src/core/protected-path-guard.js +1566 -0
- package/dist/src/core/protected-path-guard.js.map +1 -0
- package/dist/src/core/registration.d.ts +25 -0
- package/dist/src/core/registration.js +39 -0
- package/dist/src/core/registration.js.map +1 -0
- package/dist/src/core/reindex.d.ts +99 -0
- package/dist/src/core/reindex.js +336 -0
- package/dist/src/core/reindex.js.map +1 -0
- package/dist/src/core/sampler.d.ts +313 -0
- package/dist/src/core/sampler.js +388 -0
- package/dist/src/core/sampler.js.map +1 -0
- package/dist/src/core/sandbox.d.ts +290 -0
- package/dist/src/core/sandbox.js +424 -0
- package/dist/src/core/sandbox.js.map +1 -0
- package/dist/src/core/seal.d.ts +165 -0
- package/dist/src/core/seal.js +290 -0
- package/dist/src/core/seal.js.map +1 -0
- package/dist/src/core/state.d.ts +505 -0
- package/dist/src/core/state.js +1009 -0
- package/dist/src/core/state.js.map +1 -0
- package/dist/src/core/task-file.d.ts +185 -0
- package/dist/src/core/task-file.js +464 -0
- package/dist/src/core/task-file.js.map +1 -0
- package/dist/src/core/telegram-config.d.ts +93 -0
- package/dist/src/core/telegram-config.js +114 -0
- package/dist/src/core/telegram-config.js.map +1 -0
- package/dist/src/core/token.d.ts +409 -0
- package/dist/src/core/token.js +561 -0
- package/dist/src/core/token.js.map +1 -0
- package/dist/src/core/validate.d.ts +138 -0
- package/dist/src/core/validate.js +0 -0
- package/dist/src/core/validate.js.map +1 -0
- package/dist/src/core/values.d.ts +137 -0
- package/dist/src/core/values.js +153 -0
- package/dist/src/core/values.js.map +1 -0
- package/dist/src/core/vault.d.ts +291 -0
- package/dist/src/core/vault.js +612 -0
- package/dist/src/core/vault.js.map +1 -0
- package/dist/src/core/verified-snapshot.d.ts +204 -0
- package/dist/src/core/verified-snapshot.js +506 -0
- package/dist/src/core/verified-snapshot.js.map +1 -0
- package/dist/src/core/verify.d.ts +336 -0
- package/dist/src/core/verify.js +549 -0
- package/dist/src/core/verify.js.map +1 -0
- package/dist/src/core/version.d.ts +8 -0
- package/dist/src/core/version.js +9 -0
- package/dist/src/core/version.js.map +1 -0
- package/dist/src/core/wysiwys.d.ts +370 -0
- package/dist/src/core/wysiwys.js +728 -0
- package/dist/src/core/wysiwys.js.map +1 -0
- package/dist/src/daemon/advance-child.d.ts +39 -0
- package/dist/src/daemon/advance-child.js +78 -0
- package/dist/src/daemon/advance-child.js.map +1 -0
- package/dist/src/daemon/advance.d.ts +466 -0
- package/dist/src/daemon/advance.js +849 -0
- package/dist/src/daemon/advance.js.map +1 -0
- package/dist/src/daemon/audit.d.ts +87 -0
- package/dist/src/daemon/audit.js +90 -0
- package/dist/src/daemon/audit.js.map +1 -0
- package/dist/src/daemon/daemon.d.ts +1180 -0
- package/dist/src/daemon/daemon.js +1988 -0
- package/dist/src/daemon/daemon.js.map +1 -0
- package/dist/src/daemon/dark-session.d.ts +64 -0
- package/dist/src/daemon/dark-session.js +119 -0
- package/dist/src/daemon/dark-session.js.map +1 -0
- package/dist/src/daemon/draw-child.d.ts +36 -0
- package/dist/src/daemon/draw-child.js +132 -0
- package/dist/src/daemon/draw-child.js.map +1 -0
- package/dist/src/daemon/draw.d.ts +154 -0
- package/dist/src/daemon/draw.js +458 -0
- package/dist/src/daemon/draw.js.map +1 -0
- package/dist/src/daemon/git-evidence.d.ts +173 -0
- package/dist/src/daemon/git-evidence.js +345 -0
- package/dist/src/daemon/git-evidence.js.map +1 -0
- package/dist/src/daemon/projection.d.ts +180 -0
- package/dist/src/daemon/projection.js +233 -0
- package/dist/src/daemon/projection.js.map +1 -0
- package/dist/src/daemon/prune.d.ts +207 -0
- package/dist/src/daemon/prune.js +376 -0
- package/dist/src/daemon/prune.js.map +1 -0
- package/dist/src/mcp/http.d.ts +113 -0
- package/dist/src/mcp/http.js +343 -0
- package/dist/src/mcp/http.js.map +1 -0
- package/dist/src/mcp/server.d.ts +265 -0
- package/dist/src/mcp/server.js +602 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/docs/adapter-api.md +106 -0
- package/docs/cli-reference.md +5716 -0
- package/docs/codex-enforced-session.md +30 -0
- package/package.json +53 -4
- package/schema/.gitkeep +0 -0
- package/schema/LICENSE +117 -0
- package/schema/codex-instance.schema.json +82 -0
- package/schema/envelope.schema.json +137 -0
- package/schema/event.schema.json +1811 -0
- package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
- package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
- package/schema/fixtures/envelope/invalid/action-missing-idempotency-key.json +15 -0
- package/schema/fixtures/envelope/invalid/action-unknown-class-format.json +14 -0
- package/schema/fixtures/envelope/invalid/confidence-out-of-range.json +11 -0
- package/schema/fixtures/envelope/invalid/est-cost-bare-number.json +14 -0
- package/schema/fixtures/envelope/invalid/est-cost-noncanonical-string.json +14 -0
- package/schema/fixtures/envelope/invalid/malformed-assignee.json +10 -0
- package/schema/fixtures/envelope/invalid/malformed-created-by.json +7 -0
- package/schema/fixtures/envelope/invalid/malformed-max-latency.json +11 -0
- package/schema/fixtures/envelope/invalid/malformed-payload-hash.json +14 -0
- package/schema/fixtures/envelope/invalid/max-cost-bare-number.json +11 -0
- package/schema/fixtures/envelope/invalid/missing-origin.json +3 -0
- package/schema/fixtures/envelope/invalid/negative-est-cost.json +14 -0
- package/schema/fixtures/envelope/invalid/unknown-state.json +7 -0
- package/schema/fixtures/envelope/invalid/unknown-top-level-field.json +8 -0
- package/schema/fixtures/envelope/valid/action-payload-hash.json +17 -0
- package/schema/fixtures/envelope/valid/actions-without-budget.json +18 -0
- package/schema/fixtures/envelope/valid/canonical.json +25 -0
- package/schema/fixtures/envelope/valid/minimal.json +7 -0
- package/schema/fixtures/envelope/valid/multi-action-executed.json +30 -0
- package/schema/fixtures/envelope/valid/record-write-stage.json +22 -0
- package/schema/fixtures/event/invalid/approval-granted-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/approval-granted-empty-batch-delivery-id.json +17 -0
- package/schema/fixtures/event/invalid/approval-granted-fifth-reaction.json +16 -0
- package/schema/fixtures/event/invalid/approval-granted-missing-actor.json +14 -0
- package/schema/fixtures/event/invalid/approval-requested-missing-action-key.json +14 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-agent-policy-drift.json +15 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-missing-reason.json +15 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-system-actor.json +15 -0
- package/schema/fixtures/event/invalid/audit-decision-refused-human-actor.json +17 -0
- package/schema/fixtures/event/invalid/audit-decision-refused-missing-code.json +16 -0
- package/schema/fixtures/event/invalid/audit-reviewed-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/audit-reviewed-loved-no-note.json +16 -0
- package/schema/fixtures/event/invalid/audit-reviewed-system-actor.json +15 -0
- package/schema/fixtures/event/invalid/bad-actor-prefix.json +15 -0
- package/schema/fixtures/event/invalid/est-cost-bare-number.json +17 -0
- package/schema/fixtures/event/invalid/execution-completed-fabricated-exit-code.json +16 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-empty-id.json +18 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-extra-field.json +19 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-id-not-string.json +18 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-missing-adapter.json +17 -0
- package/schema/fixtures/event/invalid/execution-failed-open-reported-by.json +16 -0
- package/schema/fixtures/event/invalid/execution-indeterminate-open-reason.json +14 -0
- package/schema/fixtures/event/invalid/execution-reconciled-agent-actor.json +17 -0
- package/schema/fixtures/event/invalid/execution-started-negative-env-stripped.json +16 -0
- package/schema/fixtures/event/invalid/gate-bypassed-missing-opened-seq.json +15 -0
- package/schema/fixtures/event/invalid/gate-closed-non-integer-opened-seq.json +13 -0
- package/schema/fixtures/event/invalid/gate-opened-agent-actor.json +16 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-absolute-path.json +14 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-agent-actor.json +14 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-missing-organ-path.json +13 -0
- package/schema/fixtures/event/invalid/harness-unknown-kind.json +18 -0
- package/schema/fixtures/event/invalid/harness-version-multiline.json +16 -0
- package/schema/fixtures/event/invalid/log-checkpoint-agent-actor.json +17 -0
- package/schema/fixtures/event/invalid/log-checkpoint-missing-signature.json +16 -0
- package/schema/fixtures/event/invalid/log-checkpoint-short-signed-hash.json +17 -0
- package/schema/fixtures/event/invalid/log-checkpoint-unknown-signature-alg.json +17 -0
- package/schema/fixtures/event/invalid/malformed-ts.json +15 -0
- package/schema/fixtures/event/invalid/missing-alg.json +14 -0
- package/schema/fixtures/event/invalid/missing-hash.json +14 -0
- package/schema/fixtures/event/invalid/non-integer-seq.json +15 -0
- package/schema/fixtures/event/invalid/payload-pruned-human-actor.json +14 -0
- package/schema/fixtures/event/invalid/payload-pruned-missing-hash.json +14 -0
- package/schema/fixtures/event/invalid/policy-declined-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/policy-proposed-missing-diff.json +19 -0
- package/schema/fixtures/event/invalid/policy-proposed-system-actor.json +26 -0
- package/schema/fixtures/event/invalid/short-hash.json +15 -0
- package/schema/fixtures/event/invalid/unknown-alg.json +15 -0
- package/schema/fixtures/event/invalid/unknown-event-type.json +15 -0
- package/schema/fixtures/event/invalid/unknown-top-level-field.json +16 -0
- package/schema/fixtures/event/valid/approval-expired.json +15 -0
- package/schema/fixtures/event/valid/approval-granted-batch.json +19 -0
- package/schema/fixtures/event/valid/approval-granted-reaction.json +16 -0
- package/schema/fixtures/event/valid/approval-granted.json +15 -0
- package/schema/fixtures/event/valid/approval-rejected.json +15 -0
- package/schema/fixtures/event/valid/approval-requested.json +19 -0
- package/schema/fixtures/event/valid/approval-revoked.json +15 -0
- package/schema/fixtures/event/valid/approval-withdrawn-policy-drift.json +17 -0
- package/schema/fixtures/event/valid/approval-withdrawn.json +16 -0
- package/schema/fixtures/event/valid/audit-decision-refused.json +20 -0
- package/schema/fixtures/event/valid/audit-reviewed-reaction.json +17 -0
- package/schema/fixtures/event/valid/audit-reviewed.json +15 -0
- package/schema/fixtures/event/valid/audit-sampled.json +14 -0
- package/schema/fixtures/event/valid/budget-exceeded.json +21 -0
- package/schema/fixtures/event/valid/envelope-drift.json +16 -0
- package/schema/fixtures/event/valid/execution-completed-harness-report.json +16 -0
- package/schema/fixtures/event/valid/execution-completed-provider-ref.json +18 -0
- package/schema/fixtures/event/valid/execution-completed.json +15 -0
- package/schema/fixtures/event/valid/execution-failed-harness-report.json +16 -0
- package/schema/fixtures/event/valid/execution-failed.json +15 -0
- package/schema/fixtures/event/valid/execution-indeterminate.json +15 -0
- package/schema/fixtures/event/valid/execution-reconciled.json +17 -0
- package/schema/fixtures/event/valid/execution-started-env-stripped.json +17 -0
- package/schema/fixtures/event/valid/execution-started.json +14 -0
- package/schema/fixtures/event/valid/gate-bypassed-harness-version.json +18 -0
- package/schema/fixtures/event/valid/gate-bypassed.json +19 -0
- package/schema/fixtures/event/valid/gate-closed.json +14 -0
- package/schema/fixtures/event/valid/gate-opened.json +16 -0
- package/schema/fixtures/event/valid/gate-organ-attested.json +14 -0
- package/schema/fixtures/event/valid/genesis-null-prev.json +14 -0
- package/schema/fixtures/event/valid/log-checkpoint.json +17 -0
- package/schema/fixtures/event/valid/payload-pruned-orphan.json +13 -0
- package/schema/fixtures/event/valid/payload-pruned.json +17 -0
- package/schema/fixtures/event/valid/policy-declined.json +16 -0
- package/schema/fixtures/event/valid/policy-proposed.json +35 -0
- package/schema/fixtures/event/valid/policy-updated.json +14 -0
- package/schema/fixtures/event/valid/reconciliation-required.json +18 -0
- package/schema/fixtures/event/valid/reconciliation-satisfied.json +17 -0
- package/schema/fixtures/event/valid/route-accepted.json +15 -0
- package/schema/fixtures/event/valid/route-proposed.json +16 -0
- package/schema/fixtures/event/valid/spec-example.json +15 -0
- package/schema/fixtures/event/valid/task-registered-harness-version.json +23 -0
- package/schema/fixtures/event/valid/task-registered.json +14 -0
- package/schema/fixtures/hash/known-answer-pre-121.json +74 -0
- package/schema/fixtures/hash/known-answer.json +74 -0
- package/schema/fixtures/policy/invalid/bad-approval-ttl.json +7 -0
- package/schema/fixtures/policy/invalid/bad-web-port.json +4 -0
- package/schema/fixtures/policy/invalid/checkpoint-key-not-base64.json +6 -0
- package/schema/fixtures/policy/invalid/class-rule-missing-autonomy.json +9 -0
- package/schema/fixtures/policy/invalid/empty-class-key.json +6 -0
- package/schema/fixtures/policy/invalid/live-rate-on-human-only.json +7 -0
- package/schema/fixtures/policy/invalid/malformed-class-key.json +6 -0
- package/schema/fixtures/policy/invalid/missing-version.json +8 -0
- package/schema/fixtures/policy/invalid/negative-limit.json +9 -0
- package/schema/fixtures/policy/invalid/non-numeric-limit.json +9 -0
- package/schema/fixtures/policy/invalid/non-positive-max-pending.json +9 -0
- package/schema/fixtures/policy/invalid/on-expiry-grant.json +8 -0
- package/schema/fixtures/policy/invalid/payload-retention-bare-number.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-compound.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-fractional.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-zero.json +4 -0
- package/schema/fixtures/policy/invalid/protected-paths-escape.json +4 -0
- package/schema/fixtures/policy/invalid/protected-paths-glob.json +4 -0
- package/schema/fixtures/policy/invalid/retro-rate-on-human-only.json +7 -0
- package/schema/fixtures/policy/invalid/retro-rate-on-manual.json +7 -0
- package/schema/fixtures/policy/invalid/retro-rate-zero.json +7 -0
- package/schema/fixtures/policy/invalid/sample-rate-too-high.json +5 -0
- package/schema/fixtures/policy/invalid/sampling-secret-env-empty.json +7 -0
- package/schema/fixtures/policy/invalid/sampling-secret-env-not-string.json +6 -0
- package/schema/fixtures/policy/invalid/skew-tolerance-compound.json +6 -0
- package/schema/fixtures/policy/invalid/unknown-autonomy.json +7 -0
- package/schema/fixtures/policy/invalid/unknown-class-rule-key.json +6 -0
- package/schema/fixtures/policy/invalid/unknown-top-level-key.json +7 -0
- package/schema/fixtures/policy/invalid/vault-passphrase-env-empty.json +6 -0
- package/schema/fixtures/policy/invalid/vault-passphrase-literal.json +6 -0
- package/schema/fixtures/policy/invalid/version-not-string.json +4 -0
- package/schema/fixtures/policy/valid/canonical.json +47 -0
- package/schema/fixtures/policy/valid/checkpoint-keys.json +18 -0
- package/schema/fixtures/policy/valid/class-approvers-limits.json +25 -0
- package/schema/fixtures/policy/valid/class-retro-rate.json +17 -0
- package/schema/fixtures/policy/valid/global-budgets.json +19 -0
- package/schema/fixtures/policy/valid/human-only.json +9 -0
- package/schema/fixtures/policy/valid/minimal.json +6 -0
- package/schema/fixtures/policy/valid/protected-paths.json +10 -0
- package/schema/fixtures/policy/valid/record-namespace.json +13 -0
- package/schema/fixtures/policy/valid/request-volume-limits.json +26 -0
- package/schema/fixtures/policy/valid/retention-and-sampling-secret.json +16 -0
- package/schema/fixtures/policy/valid/skew-tolerance.json +15 -0
- package/schema/fixtures/policy/valid/vault-passphrase-env.json +14 -0
- package/schema/fixtures/policy/valid/wildcards.json +15 -0
- package/schema/fixtures/policy-md/invalid/alias-bomb.md +15 -0
- package/schema/fixtures/policy-md/invalid/no-fence.md +7 -0
- package/schema/fixtures/policy-md/invalid/protected-route-not-a-subclass.md +16 -0
- package/schema/fixtures/policy-md/invalid/schema-invalid-autonomy.md +16 -0
- package/schema/fixtures/policy-md/invalid/schema-invalid-read-proof.md +17 -0
- package/schema/fixtures/policy-md/invalid/two-fences.md +19 -0
- package/schema/fixtures/policy-md/invalid/unclosed-fence.md +11 -0
- package/schema/fixtures/policy-md/invalid/wrong-info-string.md +11 -0
- package/schema/fixtures/policy-md/invalid/yaml-syntax-error.md +13 -0
- package/schema/fixtures/policy-md/precedence/both/APPROVAL.md +7 -0
- package/schema/fixtures/policy-md/precedence/both/APPROVALS.md +7 -0
- package/schema/fixtures/policy-md/precedence/fallback-only/APPROVALS.md +7 -0
- package/schema/fixtures/policy-md/valid/canonical.md +50 -0
- package/schema/fixtures/policy-md/valid/daemon-read-proof.md +18 -0
- package/schema/fixtures/policy-md/valid/minimal.md +3 -0
- package/schema/fixtures/policy-md/valid/prose-lookalikes.md +54 -0
- package/schema/fixtures/policy-md/valid/routed-protected-paths.md +49 -0
- package/schema/fixtures/policy-md/valid/with-values.md +79 -0
- package/schema/fixtures/sample-record/invalid/bad-date-time.json +4 -0
- package/schema/fixtures/sample-record/invalid/missing-required-field.json +3 -0
- package/schema/fixtures/sample-record/invalid/unknown-top-level-field.json +5 -0
- package/schema/fixtures/sample-record/invalid/wrong-type.json +4 -0
- package/schema/fixtures/sample-record/valid/minimal.json +4 -0
- package/schema/fixtures/sample-record/valid/with-note.json +5 -0
- package/schema/fixtures/values/invalid/class-shaped.json +9 -0
- package/schema/fixtures/values/invalid/duplicate-entry.json +4 -0
- package/schema/fixtures/values/invalid/non-string-item.json +4 -0
- package/schema/fixtures/values/invalid/over-cap.json +26 -0
- package/schema/fixtures/values/invalid/unknown-key.json +5 -0
- package/schema/fixtures/values/invalid/version-string.json +1 -0
- package/schema/fixtures/values/valid/empty-lists.json +7 -0
- package/schema/fixtures/values/valid/full.json +20 -0
- package/schema/fixtures/values/valid/minimal.json +1 -0
- package/schema/fixtures/values-md/invalid/schema-invalid.md +62 -0
- package/schema/fixtures/values-md/invalid/two-blocks.md +69 -0
- package/schema/fixtures/values-md/invalid/unterminated.md +61 -0
- package/schema/fixtures/values-md/invalid/yaml-error.md +63 -0
- package/schema/fixtures/values-md/valid/absent.md +50 -0
- package/schema/fixtures/values-md/valid/with-values.md +79 -0
- package/schema/policy.schema.json +501 -0
- package/schema/sample-record.schema.json +26 -0
- package/schema/values.schema.json +55 -0
- package/templates/codex/README.md +9 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-event git commits — SPEC.md §8's optional hardening (APRV-42).
|
|
3
|
+
*
|
|
4
|
+
* > "Optionally, the log directory is a git repo and the daemon commits per
|
|
5
|
+
* > event with its own identity, giving signed, distributed tamper evidence for
|
|
6
|
+
* > free."
|
|
7
|
+
*
|
|
8
|
+
* The chain in `events.jsonl` already detects mutation and truncation on its
|
|
9
|
+
* own. What a git repository adds is a *second, independent* record of the same
|
|
10
|
+
* bytes: a mutation that is plausible against one layer has to be plausible
|
|
11
|
+
* against the other at the same time, and the second layer is one an operator
|
|
12
|
+
* can clone, mirror, and diff from somewhere the tamperer does not control.
|
|
13
|
+
* Neither layer is trusted to police the other, which is the point of having
|
|
14
|
+
* two: `approval log verify` never consults git, and nothing here ever reads a
|
|
15
|
+
* verdict out of a commit.
|
|
16
|
+
*
|
|
17
|
+
* ## Opt-in, and only for a standalone log deployment
|
|
18
|
+
*
|
|
19
|
+
* This is off unless the operator asks for it, and refuses to turn on unless the
|
|
20
|
+
* log's own directory is a repository *root*. The two layouts do not mix:
|
|
21
|
+
*
|
|
22
|
+
* - **Standalone log deployment.** The log home (`.approval/`, or whatever
|
|
23
|
+
* directory holds the log when it is not under a `log/` folder) is its own git
|
|
24
|
+
* repository, containing the log, the payload store, and nothing else. Enable
|
|
25
|
+
* the opt-in here.
|
|
26
|
+
* - **Nested project layout** — this repository's own dogfood arrangement, where
|
|
27
|
+
* `.approval/` is committed as part of a larger project repo. Perfectly valid,
|
|
28
|
+
* and the opt-in is REFUSED for it.
|
|
29
|
+
*
|
|
30
|
+
* Why refuse the nested case rather than make it work? Because a hash chain does
|
|
31
|
+
* not survive a merge. Two branches that each append independently produce a
|
|
32
|
+
* chain that is corrupt by construction, and no merge strategy repairs the
|
|
33
|
+
* semantics. An outer repository's ordinary history operations — rebase, amend,
|
|
34
|
+
* squash, force-push, `filter-branch` — rewrite the very bytes the evidence is
|
|
35
|
+
* made of, and a daemon committing into someone else's branch would be a second
|
|
36
|
+
* writer to a history the project's humans also write. Evidence that the subject
|
|
37
|
+
* of the investigation can rewrite is not evidence. So the runtime does not try
|
|
38
|
+
* to be clever about it: own-root repository, or no git evidence at all.
|
|
39
|
+
*
|
|
40
|
+
* ## What it does, precisely
|
|
41
|
+
*
|
|
42
|
+
* After every tick in which the log moved, the daemon calls {@link
|
|
43
|
+
* GitEvidenceRecorder.commit} with the verified head it just read. The recorder
|
|
44
|
+
* stages the log file and the payload store, and commits with a message naming
|
|
45
|
+
* the head's `(seq, hash)`. Batching is **one commit per tick**, not literally
|
|
46
|
+
* one per event: ticks are the only moment the daemon has a verified head in
|
|
47
|
+
* hand, and a commit is only meaningful against a head that verified. A tick
|
|
48
|
+
* that observed three appends produces one commit naming the new head and the
|
|
49
|
+
* number of records it covers — the intermediate states are still fully
|
|
50
|
+
* recoverable from the log itself, which is the artifact being witnessed.
|
|
51
|
+
*
|
|
52
|
+
* ## What it deliberately does not do
|
|
53
|
+
*
|
|
54
|
+
* It never pushes, never fetches, never creates or moves a branch by name, never
|
|
55
|
+
* touches a remote, and never writes to any git config outside the single
|
|
56
|
+
* `git commit` invocation (identity is passed with `-c`, per command, so the
|
|
57
|
+
* operator's `user.name` is neither read into the commit nor overwritten on
|
|
58
|
+
* disk). Commits are local, to the log's own repository, authored by the daemon
|
|
59
|
+
* as itself. A failure to commit is a warning, never a stop: git evidence is
|
|
60
|
+
* hardening on top of the chain, and a daemon that halted approvals because a
|
|
61
|
+
* disk was full of git objects would have converted a redundancy into a
|
|
62
|
+
* dependency.
|
|
63
|
+
*/
|
|
64
|
+
import { spawnSync } from "node:child_process";
|
|
65
|
+
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
66
|
+
import { basename, dirname, join } from "node:path";
|
|
67
|
+
import { childEnvironment } from "../core/child-env.js";
|
|
68
|
+
import { PAYLOAD_STORE_DIRNAME } from "../core/payload-store.js";
|
|
69
|
+
/**
|
|
70
|
+
* The daemon's own git identity. Never the operator's: a commit that says a
|
|
71
|
+
* human made it is a false statement about who wrote the evidence, and the whole
|
|
72
|
+
* value of the second layer is that its authorship is unambiguous.
|
|
73
|
+
*
|
|
74
|
+
* The version is pinned to `package.json` by a test rather than read at runtime,
|
|
75
|
+
* because a module that resolves its own package root differs between the source
|
|
76
|
+
* tree and the build output for no benefit at all.
|
|
77
|
+
*/
|
|
78
|
+
export const APPROVALD_VERSION = "0.2.0";
|
|
79
|
+
/** `user.name` on every commit this module makes. */
|
|
80
|
+
export const GIT_EVIDENCE_AUTHOR_NAME = `approvald ${APPROVALD_VERSION}`;
|
|
81
|
+
/** `user.email` on every commit: fixed, and deliberately undeliverable. */
|
|
82
|
+
export const GIT_EVIDENCE_AUTHOR_EMAIL = "approvald@noreply.approval.md";
|
|
83
|
+
/**
|
|
84
|
+
* Why enabling git evidence was refused. **Frozen union**, additive-only, in the
|
|
85
|
+
* same sense as every other refusal vocabulary in this codebase (SPEC.md §11.1
|
|
86
|
+
* invariant 6: refusals are machine-readable and distinct). An operator's
|
|
87
|
+
* supervisor branches on these to tell "install git" apart from "your layout is
|
|
88
|
+
* wrong", and the repair differs for every one of them.
|
|
89
|
+
*/
|
|
90
|
+
export const GIT_EVIDENCE_REFUSAL_CODES = [
|
|
91
|
+
/** No usable `git` on PATH. The daemon runs fine without the opt-in. */
|
|
92
|
+
"git-unavailable",
|
|
93
|
+
/** The directory that would hold the evidence repository does not exist. */
|
|
94
|
+
"log-dir-missing",
|
|
95
|
+
/** It exists and is not a git repository. The repair is `git init` there. */
|
|
96
|
+
"log-dir-not-repo",
|
|
97
|
+
/**
|
|
98
|
+
* It is inside a working tree it does not own — either some outer repository
|
|
99
|
+
* tracks it, or it is a repository whose root is somewhere above. Hash chains
|
|
100
|
+
* do not survive merges and an outer history rewrites evidence.
|
|
101
|
+
*/
|
|
102
|
+
"log-dir-nested",
|
|
103
|
+
];
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Layout
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
/**
|
|
108
|
+
* The directory that must be the evidence repository's root, for a given log.
|
|
109
|
+
*
|
|
110
|
+
* The same rule `payloadStoreDirFor` uses, for the same reason: SPEC.md §9 fixes
|
|
111
|
+
* the log at `<home>/log/events.jsonl` and the payload store at
|
|
112
|
+
* `<home>/payloads/`, so the only directory that contains *both* is `<home>`.
|
|
113
|
+
* Rooting the repository at the log's immediate directory would leave every
|
|
114
|
+
* payload file outside the evidence, which is precisely where a tamperer would
|
|
115
|
+
* then work. When a caller points `--log` somewhere flatter, the log's own
|
|
116
|
+
* directory is the home and the rule still holds.
|
|
117
|
+
*/
|
|
118
|
+
export function evidenceRootFor(logPath) {
|
|
119
|
+
const logDir = dirname(logPath);
|
|
120
|
+
return basename(logDir) === "log" ? dirname(logDir) : logDir;
|
|
121
|
+
}
|
|
122
|
+
function detail(cause) {
|
|
123
|
+
return cause instanceof Error ? cause.message : String(cause);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* One git invocation, non-interactive.
|
|
127
|
+
*
|
|
128
|
+
* `GIT_TERMINAL_PROMPT=0` and an emptied `GIT_DIR`/`GIT_WORK_TREE` keep an
|
|
129
|
+
* inherited environment from redirecting the command at some other repository,
|
|
130
|
+
* and nothing here ever prompts: a daemon blocked on a credential prompt is a
|
|
131
|
+
* daemon that has silently stopped.
|
|
132
|
+
*
|
|
133
|
+
* The environment is built by the APRV-205 scrub rather than copied. The daemon
|
|
134
|
+
* spawns no granted command (it advances the log and never executes an action),
|
|
135
|
+
* so this is not the task's load-bearing case; it is the daemon being the
|
|
136
|
+
* process that holds the passphrase and the token, and `git log` having no use
|
|
137
|
+
* for either.
|
|
138
|
+
*/
|
|
139
|
+
function git(args, cwd) {
|
|
140
|
+
const env = { ...childEnvironment().env, GIT_TERMINAL_PROMPT: "0" };
|
|
141
|
+
delete env["GIT_DIR"];
|
|
142
|
+
delete env["GIT_WORK_TREE"];
|
|
143
|
+
const result = spawnSync("git", args, { cwd, encoding: "utf8", env });
|
|
144
|
+
if (result.error !== undefined || result.status === null) {
|
|
145
|
+
return { ok: false, stdout: "", stderr: detail(result.error ?? "git did not run") };
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
ok: result.status === 0,
|
|
149
|
+
stdout: result.stdout ?? "",
|
|
150
|
+
stderr: result.stderr ?? "",
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** A path with symlinks resolved, or the path itself when it cannot be. */
|
|
154
|
+
function real(path) {
|
|
155
|
+
try {
|
|
156
|
+
return realpathSync(path);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return path;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** The working tree root containing `dir`, or `null` when there is none. */
|
|
163
|
+
function topLevel(dir) {
|
|
164
|
+
const result = git(["rev-parse", "--show-toplevel"], dir);
|
|
165
|
+
if (!result.ok)
|
|
166
|
+
return null;
|
|
167
|
+
const root = result.stdout.trim();
|
|
168
|
+
return root.length === 0 ? null : root;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Check every precondition and, when they all hold, build the recorder.
|
|
172
|
+
*
|
|
173
|
+
* Fail closed and fail *loudly*: each refusal is distinct, names the directory
|
|
174
|
+
* it judged, and states the repair. An operator who mistyped `--log` and an
|
|
175
|
+
* operator whose log lives inside a project repository need different sentences,
|
|
176
|
+
* and a single "git evidence unavailable" would have sent both of them looking
|
|
177
|
+
* in the wrong place.
|
|
178
|
+
*/
|
|
179
|
+
export function enableGitEvidence(logPath, sink) {
|
|
180
|
+
const root = evidenceRootFor(logPath);
|
|
181
|
+
const version = git(["--version"], process.cwd());
|
|
182
|
+
if (!version.ok) {
|
|
183
|
+
return {
|
|
184
|
+
ok: false,
|
|
185
|
+
code: "git-unavailable",
|
|
186
|
+
message: `--git-evidence needs a working \`git\` on PATH and none ran (${version.stderr.trim()}); install git, or drop the flag — the daemon's hash chain is unaffected either way`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
let isDir = false;
|
|
190
|
+
try {
|
|
191
|
+
isDir = statSync(root).isDirectory();
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
isDir = false;
|
|
195
|
+
}
|
|
196
|
+
if (!isDir) {
|
|
197
|
+
return {
|
|
198
|
+
ok: false,
|
|
199
|
+
code: "log-dir-missing",
|
|
200
|
+
message: `--git-evidence would commit into ${root}, which is not a directory; create the log's home first (the evidence repository is rooted where the log and its payload store both live)`,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const own = topLevel(root);
|
|
204
|
+
if (own === null) {
|
|
205
|
+
return {
|
|
206
|
+
ok: false,
|
|
207
|
+
code: "log-dir-not-repo",
|
|
208
|
+
message: `--git-evidence requires ${root} to be a git repository of its own and it is not one; run \`git init\` in ${root} and re-run. It must be its OWN root: a log tracked by some outer repository is evidence that repository's history operations can rewrite`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (real(own) !== real(root)) {
|
|
212
|
+
return {
|
|
213
|
+
ok: false,
|
|
214
|
+
code: "log-dir-nested",
|
|
215
|
+
message: `--git-evidence requires ${root} to be its own repository root, and it sits inside the working tree rooted at ${own}. Refused: a hash chain does not survive a merge (two branches appending independently produce a corrupt chain by construction, and no merge strategy repairs it), and an outer repository's rebases, amends and force-pushes rewrite the bytes the evidence is made of. Either run \`git init\` in ${root} so the log deployment stands alone, or run without --git-evidence — the nested layout is fully valid, it just gets its tamper evidence from the chain alone`,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
// An own-root repository can still be *contained* by an outer working tree
|
|
219
|
+
// (a nested repo inside a project checkout, this repository's own dogfood
|
|
220
|
+
// shape if someone ran `git init` in `.approval/`). The parent directory is
|
|
221
|
+
// the only place that shows it, and containment is exactly the hazard: the
|
|
222
|
+
// outer repo's operations move the directory these commits live in.
|
|
223
|
+
const parent = dirname(root);
|
|
224
|
+
if (parent !== root && existsSync(parent)) {
|
|
225
|
+
const outer = topLevel(parent);
|
|
226
|
+
if (outer !== null) {
|
|
227
|
+
return {
|
|
228
|
+
ok: false,
|
|
229
|
+
code: "log-dir-nested",
|
|
230
|
+
message: `--git-evidence requires a standalone log deployment, and ${root} — though a repository root itself — is nested inside the working tree rooted at ${outer}. Refused: the outer repository's history operations rewrite or relocate the directory these commits witness, and a hash chain does not survive a merge. Move the log outside that working tree, or run without --git-evidence (the nested layout is valid; it relies on the chain alone)`,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return { ok: true, root, recorder: new GitEvidence(root, logPath, sink) };
|
|
235
|
+
}
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
// Committing
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
/**
|
|
240
|
+
* The recorder proper: stateless except for the last head it committed, which
|
|
241
|
+
* exists only so a tick with nothing new does no git work at all.
|
|
242
|
+
*/
|
|
243
|
+
class GitEvidence {
|
|
244
|
+
root;
|
|
245
|
+
logPath;
|
|
246
|
+
sink;
|
|
247
|
+
lastSeq = null;
|
|
248
|
+
constructor(root, logPath, sink) {
|
|
249
|
+
this.root = root;
|
|
250
|
+
this.logPath = logPath;
|
|
251
|
+
this.sink = sink;
|
|
252
|
+
}
|
|
253
|
+
commit(head) {
|
|
254
|
+
// An empty log has nothing to witness, and a head that has not moved since
|
|
255
|
+
// the last commit has already been witnessed. Payload files land with the
|
|
256
|
+
// event that references them, so the head is a sound trigger for both.
|
|
257
|
+
if (head === null)
|
|
258
|
+
return;
|
|
259
|
+
if (this.lastSeq !== null && head.seq <= this.lastSeq)
|
|
260
|
+
return;
|
|
261
|
+
const paths = [this.logPath];
|
|
262
|
+
const payloads = join(this.root, PAYLOAD_STORE_DIRNAME);
|
|
263
|
+
if (existsSync(payloads))
|
|
264
|
+
paths.push(payloads);
|
|
265
|
+
const staged = this.run(["add", "--", ...paths], "add");
|
|
266
|
+
if (!staged)
|
|
267
|
+
return;
|
|
268
|
+
// Nothing staged means the log on disk is byte-identical to the committed
|
|
269
|
+
// one. That is not a failure and it is not silence worth reporting: it is
|
|
270
|
+
// the ordinary case for a tick whose appends were already committed.
|
|
271
|
+
const pending = git(["diff", "--cached", "--quiet"], this.root);
|
|
272
|
+
if (pending.ok) {
|
|
273
|
+
this.lastSeq = head.seq;
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
// The batch size, taken from git rather than from a remembered sequence
|
|
277
|
+
// number: the log is append-only, so staged added lines *are* the records
|
|
278
|
+
// this commit covers, and the count stays right across a daemon restart
|
|
279
|
+
// that has no memory of the previous commit at all.
|
|
280
|
+
const records = this.stagedRecords();
|
|
281
|
+
const committed = this.run([
|
|
282
|
+
"-c",
|
|
283
|
+
`user.name=${GIT_EVIDENCE_AUTHOR_NAME}`,
|
|
284
|
+
"-c",
|
|
285
|
+
`user.email=${GIT_EVIDENCE_AUTHOR_EMAIL}`,
|
|
286
|
+
"-c",
|
|
287
|
+
"commit.gpgsign=false",
|
|
288
|
+
"commit",
|
|
289
|
+
"--no-verify",
|
|
290
|
+
"--quiet",
|
|
291
|
+
"-m",
|
|
292
|
+
message(head, records),
|
|
293
|
+
], "commit");
|
|
294
|
+
if (!committed)
|
|
295
|
+
return;
|
|
296
|
+
const sha = git(["rev-parse", "--short", "HEAD"], this.root);
|
|
297
|
+
this.lastSeq = head.seq;
|
|
298
|
+
this.sink({
|
|
299
|
+
event: "git_evidence",
|
|
300
|
+
commit: sha.ok ? sha.stdout.trim() : "unknown",
|
|
301
|
+
seq: head.seq,
|
|
302
|
+
hash: head.hash,
|
|
303
|
+
records,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
/** Staged added lines of the log file, or `null` when git would not say. */
|
|
307
|
+
stagedRecords() {
|
|
308
|
+
const numstat = git(["diff", "--cached", "--numstat", "--", this.logPath], this.root);
|
|
309
|
+
if (!numstat.ok)
|
|
310
|
+
return null;
|
|
311
|
+
const added = numstat.stdout.trim().split("\n")[0]?.split("\t")[0];
|
|
312
|
+
if (added === undefined)
|
|
313
|
+
return null;
|
|
314
|
+
const count = Number(added);
|
|
315
|
+
return Number.isInteger(count) ? count : null;
|
|
316
|
+
}
|
|
317
|
+
/** One git step, reporting a failure as a warning and never throwing. */
|
|
318
|
+
run(args, step) {
|
|
319
|
+
const result = git(args, this.root);
|
|
320
|
+
if (result.ok)
|
|
321
|
+
return true;
|
|
322
|
+
this.sink({
|
|
323
|
+
event: "git_evidence_failed",
|
|
324
|
+
step,
|
|
325
|
+
message: `git ${step} in ${this.root} failed: ${(result.stderr.trim() || result.stdout.trim()) === ""
|
|
326
|
+
? "no output"
|
|
327
|
+
: result.stderr.trim() || result.stdout.trim()}; the log itself is untouched and its hash chain is the primary evidence`,
|
|
328
|
+
});
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* The commit message: the head's `(seq, hash)` on the subject line, so a reader
|
|
334
|
+
* of `git log --oneline` can check a commit against the chain without opening
|
|
335
|
+
* anything, and the batch size in the body so the per-tick batching is visible
|
|
336
|
+
* rather than inferred.
|
|
337
|
+
*/
|
|
338
|
+
export function message(head, records) {
|
|
339
|
+
const subject = `seq ${String(head.seq)} sha256:${head.hash}`;
|
|
340
|
+
const covered = records === null
|
|
341
|
+
? "record count unavailable"
|
|
342
|
+
: `${String(records)} record(s) since the previous commit`;
|
|
343
|
+
return `${subject}\n\napprovald ${APPROVALD_VERSION} tamper evidence: ${covered}.\nOne commit per daemon tick, witnessing the verified head named above.\n`;
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=git-evidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-evidence.js","sourceRoot":"","sources":["../../../src/daemon/git-evidence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon's pure projections (SPEC.md §6.3, §10.2).
|
|
3
|
+
*
|
|
4
|
+
* Everything the daemon *decides* lives here, and everything it *does* lives in
|
|
5
|
+
* `daemon.ts`. The split is the same one `core/loop.ts` draws for loop safety:
|
|
6
|
+
* a projection over verified records is a pure function of (records, instant,
|
|
7
|
+
* TTL), so it can be replayed, unit-tested against an injected clock, and never
|
|
8
|
+
* disagrees with itself between two callers.
|
|
9
|
+
*
|
|
10
|
+
* Nothing here reads the clock, the filesystem, or the network, and nothing
|
|
11
|
+
* here appends. Three questions are answered:
|
|
12
|
+
*
|
|
13
|
+
* 1. **What does the log say a task's envelope `state:` should be?**
|
|
14
|
+
* {@link taskEnvelopeState}. §6.3: "`state` is a projection of log events;
|
|
15
|
+
* the file is updated by the daemon after the event is appended, never the
|
|
16
|
+
* reverse." The daemon compares the file's claim against this answer, and a
|
|
17
|
+
* file that contradicts it is `envelope.drift`.
|
|
18
|
+
* 2. **Which live requests have lapsed with no `approval.expired` on record?**
|
|
19
|
+
* {@link lapsedRequests}. The gate already judges TTL lazily at decision
|
|
20
|
+
* time (a late grant is refused whether or not an expiry event exists), so
|
|
21
|
+
* the sweep changes no verdict; it makes the verdict *visible* in the log
|
|
22
|
+
* and in every projection built from it.
|
|
23
|
+
* 3. **Has this exact drift already been recorded?** {@link driftAlreadyLogged}.
|
|
24
|
+
* A watcher fires on every save and the periodic tick re-scans regardless,
|
|
25
|
+
* so without a dedupe rule one unfixed file would append an unbounded run of
|
|
26
|
+
* identical events. The rule is stated on that function.
|
|
27
|
+
*
|
|
28
|
+
* The state derivation itself is NOT reimplemented here: every action's state
|
|
29
|
+
* comes from `core/state.ts`'s `requestState`, the same derivation the gate,
|
|
30
|
+
* the token module, and the executor read. This module only rolls action states
|
|
31
|
+
* up to the task level, and that rollup is the one new rule it owns.
|
|
32
|
+
*/
|
|
33
|
+
import type { EventRecord } from "../core/log.js";
|
|
34
|
+
import { type RequestDerivation } from "../core/state.js";
|
|
35
|
+
/**
|
|
36
|
+
* The envelope's `state:` vocabulary (`envelope.schema.json`, SPEC.md §6.3).
|
|
37
|
+
*
|
|
38
|
+
* Spelled here rather than imported from the schema because the schema is data
|
|
39
|
+
* read at runtime and this is a type; `tests/daemon-projection.test.ts` pins the
|
|
40
|
+
* two against each other so they cannot drift apart.
|
|
41
|
+
*/
|
|
42
|
+
export declare const ENVELOPE_STATES: readonly ["proposed", "awaiting", "approved", "executed", "rejected", "expired", "revoked"];
|
|
43
|
+
export type EnvelopeState = (typeof ENVELOPE_STATES)[number];
|
|
44
|
+
/** Is this the envelope's `state:` value? Used to read an untrusted file. */
|
|
45
|
+
export declare function isEnvelopeState(value: unknown): value is EnvelopeState;
|
|
46
|
+
/** One declared action of a task, as the log records it, with its derived state. */
|
|
47
|
+
export interface ActionProjection {
|
|
48
|
+
actionKey: string;
|
|
49
|
+
derivation: RequestDerivation;
|
|
50
|
+
}
|
|
51
|
+
/** What the log says about one task. */
|
|
52
|
+
export interface TaskProjection {
|
|
53
|
+
task: string;
|
|
54
|
+
/** A `task.registered` record exists for this task id. */
|
|
55
|
+
registered: boolean;
|
|
56
|
+
/** The envelope `state:` the log implies (SPEC.md §6.3). */
|
|
57
|
+
state: EnvelopeState;
|
|
58
|
+
/** Every action key the latest registration declared, with its derivation. */
|
|
59
|
+
actions: ActionProjection[];
|
|
60
|
+
}
|
|
61
|
+
/** Every action key the latest `task.registered` for `task` declared, in order. */
|
|
62
|
+
export declare function registeredActionKeys(records: EventRecord[], task: string): string[];
|
|
63
|
+
/**
|
|
64
|
+
* The envelope `state:` the log implies for `task`, at instant `ts`.
|
|
65
|
+
*
|
|
66
|
+
* ## The rollup rule, stated once
|
|
67
|
+
*
|
|
68
|
+
* §6.3's lifecycle is drawn for one action; a task may declare several, so the
|
|
69
|
+
* projection needs a rule for a task whose actions disagree. It is this, in
|
|
70
|
+
* order, and the order is the point:
|
|
71
|
+
*
|
|
72
|
+
* 1. any action with a live request → **awaiting**. A human owes an answer, and
|
|
73
|
+
* that fact outranks every other, because it is the only state that asks
|
|
74
|
+
* something of a person.
|
|
75
|
+
* 2. else any granted action that has not executed → **approved**.
|
|
76
|
+
* 3. else any action with an `execution.completed` → **executed**.
|
|
77
|
+
* 4. else **revoked**, then **rejected**, then **expired** — human decisions
|
|
78
|
+
* outrank a runtime lapse, so a task with one revoked and one expired action
|
|
79
|
+
* reads as revoked, naming the decision a person actually made.
|
|
80
|
+
* 5. else **proposed**: registered (or not) and nothing has happened.
|
|
81
|
+
*
|
|
82
|
+
* A task with exactly one action — the common case — collapses to §6.3's
|
|
83
|
+
* lifecycle exactly, which is the property the rule was chosen for.
|
|
84
|
+
*
|
|
85
|
+
* An unregistered task projects to `proposed`: the log knows of no declaration,
|
|
86
|
+
* so nothing has been proposed *to the gate* yet. A file claiming `approved`
|
|
87
|
+
* for a task the log never registered therefore contradicts the log, which is
|
|
88
|
+
* exactly the reading §6.3 wants.
|
|
89
|
+
*/
|
|
90
|
+
export declare function taskEnvelopeState(records: EventRecord[], task: string, ts: string, ttlMs: number | null): TaskProjection;
|
|
91
|
+
/** One request the TTL sweep would materialise an `approval.expired` for. */
|
|
92
|
+
export interface LapsedRequest {
|
|
93
|
+
actionKey: string;
|
|
94
|
+
task: string | null;
|
|
95
|
+
/** The `ts` of the `approval.requested` that lapsed. */
|
|
96
|
+
requestedTs: string | null;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Live requests whose TTL has lapsed and which carry no `approval.expired`.
|
|
100
|
+
*
|
|
101
|
+
* Idempotence is structural rather than remembered: the answer is re-derived
|
|
102
|
+
* from the verified log every sweep, and an action whose expiry has been
|
|
103
|
+
* appended no longer satisfies the predicate. Two sweeps over the same log
|
|
104
|
+
* therefore produce the same list, and a sweep that follows a successful one
|
|
105
|
+
* produces an empty list — with no state carried between them, and no way for a
|
|
106
|
+
* restarted daemon to expire something twice.
|
|
107
|
+
*
|
|
108
|
+
* `ttlMs === null` (a policy that declares no `defaults.approval_ttl`) yields no
|
|
109
|
+
* candidates at all: nothing lapses when nothing was bounded, and inventing a
|
|
110
|
+
* deadline is not the daemon's to invent.
|
|
111
|
+
*
|
|
112
|
+
* Returned in first-request order, so a sweep's appends land in a deterministic
|
|
113
|
+
* sequence.
|
|
114
|
+
*/
|
|
115
|
+
export declare function lapsedRequests(records: EventRecord[], ts: string, ttlMs: number | null): LapsedRequest[];
|
|
116
|
+
/**
|
|
117
|
+
* Why an `envelope.drift` record was written (APRV-63).
|
|
118
|
+
*
|
|
119
|
+
* `state-mismatch` is the original reading of SPEC.md §6.3: the file makes a
|
|
120
|
+
* claim about `state:` and the log implies another one. `envelope-missing` is
|
|
121
|
+
* the loss case observed live in APRV-60: the log holds a `task.registered` for
|
|
122
|
+
* the task, and the file that declared it now carries no `approval:` key at all.
|
|
123
|
+
* They are separated because they call for different human actions — one is an
|
|
124
|
+
* edit to reconcile, the other is a *deletion to restore* — and a reader who
|
|
125
|
+
* could not tell them apart would treat a lost envelope as a stale one.
|
|
126
|
+
*
|
|
127
|
+
* `reason` is absent from records written before this vocabulary existed;
|
|
128
|
+
* readers (including {@link driftAlreadyLogged}) treat absence as
|
|
129
|
+
* `state-mismatch`, which is what every such record was.
|
|
130
|
+
*/
|
|
131
|
+
export declare const DRIFT_REASONS: readonly ["state-mismatch", "envelope-missing"];
|
|
132
|
+
export type DriftReason = (typeof DRIFT_REASONS)[number];
|
|
133
|
+
export { latestRegistration } from "../core/registration.js";
|
|
134
|
+
/** The facts one `envelope.drift` record carries, and the dedupe key. */
|
|
135
|
+
export interface DriftFacts {
|
|
136
|
+
/** The `state:` the file claims, or `null` when it declares none. */
|
|
137
|
+
declaredState: string | null;
|
|
138
|
+
/** The state the log implies (SPEC.md §6.3). */
|
|
139
|
+
derivedState: EnvelopeState;
|
|
140
|
+
/**
|
|
141
|
+
* SHA-256 over the RFC 8785 form of the file's whole `approval:` envelope, or
|
|
142
|
+
* `null` when the envelope could not be canonicalized. Part of the dedupe key
|
|
143
|
+
* so that editing a file from one contradiction into a different one is a new
|
|
144
|
+
* drift and not a suppressed one.
|
|
145
|
+
*/
|
|
146
|
+
envelopeDigest: string | null;
|
|
147
|
+
/**
|
|
148
|
+
* Which kind of drift this is (APRV-63). Part of the dedupe key: a file that
|
|
149
|
+
* contradicts the log and a file that lost its envelope are different facts
|
|
150
|
+
* about the same task, and neither may suppress the other. Absent means
|
|
151
|
+
* `state-mismatch`, matching every record written before the vocabulary
|
|
152
|
+
* existed.
|
|
153
|
+
*/
|
|
154
|
+
reason?: DriftReason;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Has this exact drift already been recorded for `task`?
|
|
158
|
+
*
|
|
159
|
+
* The rule: compare against the **latest** `envelope.drift` for the task. Equal
|
|
160
|
+
* `(reason, declared_state, derived_state, envelope_sha256)` means the situation
|
|
161
|
+
* the log already describes is the situation now, so nothing is appended. Any
|
|
162
|
+
* difference
|
|
163
|
+
* — the human edited the file again, or the log moved and the derived state
|
|
164
|
+
* changed — is a new fact and is recorded.
|
|
165
|
+
*
|
|
166
|
+
* Comparing against the latest record rather than against any record is
|
|
167
|
+
* deliberate: a task that drifts, is repaired, and drifts the same way again has
|
|
168
|
+
* genuinely drifted twice, and an audit that collapsed those into one would be
|
|
169
|
+
* hiding a repetition from the person whose attention this system spends.
|
|
170
|
+
*
|
|
171
|
+
* For `envelope-missing` (APRV-63) the same rule reads as: one record per
|
|
172
|
+
* episode of loss, re-derived every tick from the file and the log rather than
|
|
173
|
+
* remembered, and a new record when the derived state moves underneath a file
|
|
174
|
+
* that is still stripped. Its limit is stated where it is felt: a file whose
|
|
175
|
+
* envelope is restored by hand *in agreement with the log* leaves no record of
|
|
176
|
+
* the restoration, so a second loss at the same derived state reads as the same
|
|
177
|
+
* episode and is not appended twice. Recording the restoration would need an
|
|
178
|
+
* event nobody has specified; detection does not invent one.
|
|
179
|
+
*/
|
|
180
|
+
export declare function driftAlreadyLogged(records: EventRecord[], task: string, facts: DriftFacts): boolean;
|