approval-md 0.3.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 +83 -914
- package/SPEC.md +98 -13
- 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 +19 -0
- package/dist/src/channels/contract.js +105 -1
- 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 +271 -1
- package/dist/src/channels/telegram.js +403 -45
- package/dist/src/channels/telegram.js.map +1 -1
- package/dist/src/cli/amend.js +350 -4
- package/dist/src/cli/amend.js.map +1 -1
- package/dist/src/cli/attest.js +43 -6
- 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 +272 -26
- package/dist/src/cli/channel-telegram.js +478 -41
- package/dist/src/cli/channel-telegram.js.map +1 -1
- package/dist/src/cli/channel.d.ts +1 -1
- package/dist/src/cli/channel.js +5 -1
- package/dist/src/cli/channel.js.map +1 -1
- package/dist/src/cli/daemon.js +37 -5
- package/dist/src/cli/daemon.js.map +1 -1
- package/dist/src/cli/doctor.d.ts +63 -0
- package/dist/src/cli/doctor.js +856 -111
- package/dist/src/cli/doctor.js.map +1 -1
- package/dist/src/cli/execute.d.ts +17 -1
- package/dist/src/cli/execute.js +341 -20
- 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 +9 -1
- package/dist/src/cli/help.js +246 -38
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hook.d.ts +371 -3
- package/dist/src/cli/hook.js +1926 -44
- package/dist/src/cli/hook.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 +51 -0
- 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/scaffold.js +6 -0
- 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/up.js +21 -2
- package/dist/src/cli/up.js.map +1 -1
- package/dist/src/cli/verb-registry.d.ts +2 -0
- package/dist/src/cli/verb-registry.js +337 -39
- 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/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 +20 -3
- package/dist/src/core/attest.js +25 -0
- package/dist/src/core/attest.js.map +1 -1
- package/dist/src/core/audit.d.ts +55 -3
- package/dist/src/core/audit.js +52 -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/command-class.d.ts +51 -0
- package/dist/src/core/command-class.js +760 -8
- package/dist/src/core/command-class.js.map +1 -1
- 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/gate.d.ts +306 -5
- package/dist/src/core/gate.js +772 -24
- package/dist/src/core/gate.js.map +1 -1
- package/dist/src/core/harness-version.d.ts +128 -4
- package/dist/src/core/harness-version.js +179 -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/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 +50 -21
- 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 +7 -1
- package/dist/src/core/policy-explain.js +16 -1
- package/dist/src/core/policy-explain.js.map +1 -1
- package/dist/src/core/policy-load.d.ts +24 -0
- package/dist/src/core/policy-load.js.map +1 -1
- package/dist/src/core/policy-match.d.ts +38 -0
- package/dist/src/core/policy-match.js +35 -0
- package/dist/src/core/policy-match.js.map +1 -1
- package/dist/src/core/policy-proposal.d.ts +23 -0
- package/dist/src/core/policy-proposal.js +8 -2
- package/dist/src/core/policy-proposal.js.map +1 -1
- package/dist/src/core/read-scope.d.ts +10 -0
- package/dist/src/core/read-scope.js +4 -0
- package/dist/src/core/read-scope.js.map +1 -1
- 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/sender-identity.d.ts +35 -10
- package/dist/src/core/sender-identity.js +48 -11
- package/dist/src/core/sender-identity.js.map +1 -1
- 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/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/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 +298 -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 +22 -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 +1633 -43
- package/package.json +4 -2
- package/schema/event.schema.json +59 -2
- 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/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-requested-harness-cap.json +18 -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/harness-kind-hermes.json +23 -0
- package/schema/fixtures/policy/invalid/daemons-malformed-id.json +10 -0
- package/schema/fixtures/policy/valid/daemons-allowlist.json +19 -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/policy.schema.json +50 -6
|
@@ -104,6 +104,12 @@ import { type PruneReason } from "./prune.js";
|
|
|
104
104
|
export declare const DAEMON_ACTOR = "system:daemon";
|
|
105
105
|
/** Backlog.md's conventional task folder, relative to the working directory. */
|
|
106
106
|
export { DEFAULT_TASKS_DIR } from "../core/registration.js";
|
|
107
|
+
/**
|
|
108
|
+
* Forget every deferral. Exported for tests, used nowhere else: the memory is
|
|
109
|
+
* output bookkeeping, so a suite that shares a process needs to be able to start
|
|
110
|
+
* from nothing and to exercise what a restarted daemon does.
|
|
111
|
+
*/
|
|
112
|
+
export declare function resetDriftDeferrals(): void;
|
|
107
113
|
/** How often the daemon looks, absent any watcher event. */
|
|
108
114
|
export declare const DEFAULT_INTERVAL_MS = 30000;
|
|
109
115
|
/** How long a burst of watcher events is allowed to settle before a tick. */
|
|
@@ -203,6 +209,18 @@ export type DaemonEvent = {
|
|
|
203
209
|
* a person.
|
|
204
210
|
*/
|
|
205
211
|
dangling_advances?: string[];
|
|
212
|
+
/**
|
|
213
|
+
* Which daemon instance this run is (APRV-383), and `null` when the id it
|
|
214
|
+
* was launched with is unusable. Additive, like every other growth of this
|
|
215
|
+
* union.
|
|
216
|
+
*
|
|
217
|
+
* On the FIRST line for the reason `read_proof` and `draw` are: it is the
|
|
218
|
+
* name every record this run appends will carry, a tenant reading a hosted
|
|
219
|
+
* log identifies the process by it, and it is not something an operator
|
|
220
|
+
* should have to ask the process about. `null` is the state in which this
|
|
221
|
+
* run will refuse every append, which the warning beside it says in words.
|
|
222
|
+
*/
|
|
223
|
+
daemon?: string | null;
|
|
206
224
|
} | {
|
|
207
225
|
event: "drift";
|
|
208
226
|
task: string;
|
|
@@ -216,6 +234,18 @@ export type DaemonEvent = {
|
|
|
216
234
|
* appeared on all of them would change a shape supervisors already parse.
|
|
217
235
|
*/
|
|
218
236
|
reason?: "envelope-missing";
|
|
237
|
+
/**
|
|
238
|
+
* This append is the one an earlier tick of THIS run deferred (APRV-403).
|
|
239
|
+
* Present only when it is true, so the shape a supervisor already parses is
|
|
240
|
+
* unchanged for every other drift record.
|
|
241
|
+
*
|
|
242
|
+
* It closes a `drift-deferred` warning, exactly as `sampled.retry` closes a
|
|
243
|
+
* `sample-deferred` one: the pair is what tells an operator that the
|
|
244
|
+
* transient failure they read resolved, and which record resolved it. A
|
|
245
|
+
* fresh process makes the same append and claims no retry, because this
|
|
246
|
+
* loop says only what it witnessed.
|
|
247
|
+
*/
|
|
248
|
+
retry?: true;
|
|
219
249
|
} | {
|
|
220
250
|
/**
|
|
221
251
|
* A task file's `state:` was rewritten to match the log (SPEC.md §6.3).
|
|
@@ -252,6 +282,18 @@ export type DaemonEvent = {
|
|
|
252
282
|
seq: number;
|
|
253
283
|
/** `seq` of the `execution.started` record the sample named. */
|
|
254
284
|
subject_seq: number;
|
|
285
|
+
/**
|
|
286
|
+
* This append is the one an earlier tick of THIS run deferred (APRV-381).
|
|
287
|
+
* Present only when it is true, so the shape a supervisor already parses is
|
|
288
|
+
* unchanged for every other sample.
|
|
289
|
+
*
|
|
290
|
+
* It closes a `sample-deferred` warning: the pair is what tells an operator
|
|
291
|
+
* that the transient failure they read resolved, and which sample resolved
|
|
292
|
+
* it. Absent on a run that did not itself defer the sample, including a
|
|
293
|
+
* fresh process picking up a deferral the previous one printed, because this
|
|
294
|
+
* loop says only what it witnessed.
|
|
295
|
+
*/
|
|
296
|
+
retry?: true;
|
|
255
297
|
} | {
|
|
256
298
|
/**
|
|
257
299
|
* A payload's bytes were removed under `payload_retention` (APRV-41,
|
|
@@ -551,6 +593,19 @@ export declare const DAEMON_WARNING_CODES: readonly [
|
|
|
551
593
|
* repair, and the next tick asks again.
|
|
552
594
|
*/
|
|
553
595
|
"anchor-behind",
|
|
596
|
+
/**
|
|
597
|
+
* The working log changed between this tick's opening read and the anchor
|
|
598
|
+
* check's own read of the file, so the check read it again (APRV-389).
|
|
599
|
+
*
|
|
600
|
+
* A line rather than a stop, and rather than a silence. `approval log sync`
|
|
601
|
+
* and a records pull both rewrite `events.jsonl` under a running daemon
|
|
602
|
+
* (baseline, fast-forward, restore), and this loop reads without the append
|
|
603
|
+
* lock, so a tick can hold a view the file has already moved past. That is a
|
|
604
|
+
* fact about reads, never a fork: the anchor comparison is made again from the
|
|
605
|
+
* file and the verdict beside this line is the second read's. The line is the
|
|
606
|
+
* one an operator acts on when the writer was not a sync they ran.
|
|
607
|
+
*/
|
|
608
|
+
"anchor-reread",
|
|
554
609
|
/**
|
|
555
610
|
* `audit.checkpoint_every` says a human-signed checkpoint is due and the log
|
|
556
611
|
* carries none that recent (APRV-220). A WARNING and never a stop, at every
|
|
@@ -566,7 +621,54 @@ export declare const DAEMON_WARNING_CODES: readonly [
|
|
|
566
621
|
* while it stands, and that is a thing to know rather than to discover from a
|
|
567
622
|
* month of taps.
|
|
568
623
|
*/
|
|
569
|
-
"draw-unavailable"
|
|
624
|
+
"draw-unavailable",
|
|
625
|
+
/**
|
|
626
|
+
* This daemon's own id is not one the attested policy's `daemons` list admits,
|
|
627
|
+
* or the id it was launched with is not a usable id at all (APRV-383).
|
|
628
|
+
*
|
|
629
|
+
* A warning rather than a stop, and the distinction matters: the refusal itself
|
|
630
|
+
* happens at the write boundary, one append at a time, so the loop keeps
|
|
631
|
+
* reading, keeps rendering the queue and keeps reporting, and writes nothing.
|
|
632
|
+
* The line exists because an operator should learn that from the first tick
|
|
633
|
+
* rather than from a day of `append-refused` messages. The repair is a line in
|
|
634
|
+
* a policy a human re-attests, or a launch environment fixed, and neither is
|
|
635
|
+
* something this process can do for itself.
|
|
636
|
+
*/
|
|
637
|
+
"daemon-identity-refused",
|
|
638
|
+
/**
|
|
639
|
+
* An `audit.sampled` append met a held lock or a moved head, so the sample was
|
|
640
|
+
* postponed to the next tick (APRV-381). Appended to this union, so no existing
|
|
641
|
+
* entry changed meaning.
|
|
642
|
+
*
|
|
643
|
+
* Distinct from `append-refused` because the operator's next move is different:
|
|
644
|
+
* `append-refused` on a sample is a fact about the record or the file and wants
|
|
645
|
+
* a person, and this is contention between writers that the next sweep resolves
|
|
646
|
+
* by re-deriving the sample from the log. It is still a warning rather than a
|
|
647
|
+
* silence, because a tick that keeps deferring is a log under contention and
|
|
648
|
+
* that is a thing to know, and the `sampled` line that closes it carries
|
|
649
|
+
* `retry`.
|
|
650
|
+
*/
|
|
651
|
+
"sample-deferred",
|
|
652
|
+
/**
|
|
653
|
+
* An `envelope.drift` append met a held lock or a moved head, so the record was
|
|
654
|
+
* postponed to the next tick (APRV-403). Appended to this union, so no existing
|
|
655
|
+
* entry changed meaning.
|
|
656
|
+
*
|
|
657
|
+
* The same split APRV-381 made for `audit.sampled`, for the same reason and
|
|
658
|
+
* from the same closed list of transient codes. Found while landing that task:
|
|
659
|
+
* the end-to-end test that holds the append lockfile for a whole tick showed
|
|
660
|
+
* the drift scan printing `append-refused … (lock-timeout)`, which is true and
|
|
661
|
+
* reads as a lost record, while the next tick re-derived the drift from the
|
|
662
|
+
* verified log and appended it. An operator's next move differs between the
|
|
663
|
+
* two: `append-refused` on a drift record is a fact about the record or the
|
|
664
|
+
* file and wants a person, and this is contention between writers that the
|
|
665
|
+
* scan resolves by itself.
|
|
666
|
+
*
|
|
667
|
+
* Still a warning rather than a silence: a scan that keeps deferring is a log
|
|
668
|
+
* under contention, which is a thing to know. The `drift` line that closes it
|
|
669
|
+
* carries `retry`.
|
|
670
|
+
*/
|
|
671
|
+
"drift-deferred"];
|
|
570
672
|
export type DaemonWarningCode = (typeof DAEMON_WARNING_CODES)[number];
|
|
571
673
|
/** Where daemon output goes. Injected, so the loop itself writes to nothing. */
|
|
572
674
|
export interface DaemonSink {
|
|
@@ -838,6 +940,16 @@ export declare class Daemon {
|
|
|
838
940
|
private previousSelfWrites;
|
|
839
941
|
private settle;
|
|
840
942
|
private finished;
|
|
943
|
+
/**
|
|
944
|
+
* What this process resolved as its own daemon id (APRV-383), kept so the
|
|
945
|
+
* `started` line can name it and the startup check can say what is wrong with
|
|
946
|
+
* it. The id in FORCE lives in `core/daemon-identity.ts`'s process state, which
|
|
947
|
+
* is what the write boundary reads; this field is the resolution that produced
|
|
948
|
+
* it, and nothing reads it to decide anything.
|
|
949
|
+
*/
|
|
950
|
+
private readonly identity;
|
|
951
|
+
/** Has the unlisted-id warning already been said this run? */
|
|
952
|
+
private reportedIdentityRefusal;
|
|
841
953
|
/** Whether {@link DaemonOptions.draw} actually bound (APRV-208). */
|
|
842
954
|
private drawServing;
|
|
843
955
|
constructor(options: DaemonOptions);
|
|
@@ -1025,6 +1137,23 @@ export declare class Daemon {
|
|
|
1025
1137
|
*/
|
|
1026
1138
|
private read;
|
|
1027
1139
|
private readOnce;
|
|
1140
|
+
/** Where this daemon's policy is, in `loadPolicy`'s own vocabulary. */
|
|
1141
|
+
private policyWhere;
|
|
1142
|
+
/**
|
|
1143
|
+
* Put the attested policy's `daemons` allowlist in force for this tick
|
|
1144
|
+
* (APRV-383).
|
|
1145
|
+
*
|
|
1146
|
+
* Called once per tick, immediately after the opening verified read and before
|
|
1147
|
+
* any sweep that appends. It never widens: a resolution that fails sets nothing,
|
|
1148
|
+
* so whatever was last resolved stays in force, and a run whose policy was never
|
|
1149
|
+
* attested is unrestricted exactly as every run before this key existed was.
|
|
1150
|
+
*
|
|
1151
|
+
* The warning is said ONCE per run. A line every thirty seconds forever stops
|
|
1152
|
+
* being read (the `reportedDangling` set above exists for the same reason), and
|
|
1153
|
+
* the write boundary is where the refusal actually happens: every refused append
|
|
1154
|
+
* carries its own `append-refused` line with the reason in it.
|
|
1155
|
+
*/
|
|
1156
|
+
private refreshIdentity;
|
|
1028
1157
|
/** The TTL in force right now, re-read every pass: policy files change. */
|
|
1029
1158
|
private ttlMs;
|
|
1030
1159
|
private gateOptions;
|
|
@@ -1045,8 +1174,46 @@ export declare class Daemon {
|
|
|
1045
1174
|
* malformed file is not a *contradiction* of the log, it is a file the runtime
|
|
1046
1175
|
* cannot read a claim out of at all, and inventing a `declared_state` for it
|
|
1047
1176
|
* would put a fact in the log that nobody wrote.
|
|
1177
|
+
*
|
|
1178
|
+
* ## A deferred drift record is not a lost one (APRV-403)
|
|
1179
|
+
*
|
|
1180
|
+
* An append here can fail two ways that call for different things. A held
|
|
1181
|
+
* lockfile or a head that moved under the compare-and-append means the log was
|
|
1182
|
+
* not written and nothing about the file changed; the next tick re-reads the
|
|
1183
|
+
* folder, re-derives the disagreement from the verified log, and appends it.
|
|
1184
|
+
* A validation refusal, a canonicalization failure, a corrupt tail or an I/O
|
|
1185
|
+
* error is a fact about the record or the file that no retry repairs.
|
|
1186
|
+
*
|
|
1187
|
+
* Both used to read as `append-refused … was not appended`, which for the
|
|
1188
|
+
* first is true and reads as a loss. So the transient half now goes out as
|
|
1189
|
+
* {@link deferDrift}'s own `drift-deferred` line, naming the task and saying
|
|
1190
|
+
* that the scan retries, and the `drift` record that closes it carries
|
|
1191
|
+
* `retry`. Everything else keeps the form it had.
|
|
1192
|
+
*
|
|
1193
|
+
* Nothing about the APPEND changed, which is the part that matters for
|
|
1194
|
+
* SPEC.md §11.1 invariant 5: the record is still placed by `appendEvent`
|
|
1195
|
+
* against the `expectedHead` of a read taken immediately before it, and the
|
|
1196
|
+
* whole decision is still remade against that read. A `head-moved` here IS
|
|
1197
|
+
* compare-and-append working — another writer landed a record between this
|
|
1198
|
+
* scan's read and its append — and deferring is the only answer that does not
|
|
1199
|
+
* either write against a head this scan never saw or lose the observation.
|
|
1048
1200
|
*/
|
|
1049
1201
|
private scanForDrift;
|
|
1202
|
+
/**
|
|
1203
|
+
* Say that an `envelope.drift` append did not happen YET, and remember it
|
|
1204
|
+
* (APRV-403).
|
|
1205
|
+
*
|
|
1206
|
+
* Two things this line has to do that `append-refused` did not. It names the
|
|
1207
|
+
* TASK KEY, so an operator can match the deferral to the record that closes
|
|
1208
|
+
* it, and it says in words that the next tick retries — because the sentence
|
|
1209
|
+
* it replaced ended at "was not appended", which is true and reads as a loss.
|
|
1210
|
+
*
|
|
1211
|
+
* The claim is safe to make because the scan carries nothing between ticks:
|
|
1212
|
+
* the next one re-reads the folder, re-derives the state from the verified
|
|
1213
|
+
* log, and finds the same disagreement, so the retry is a property of how the
|
|
1214
|
+
* scan is written rather than a promise this method is keeping.
|
|
1215
|
+
*/
|
|
1216
|
+
private deferDrift;
|
|
1050
1217
|
/** Every `*.md` under the task folder, sorted, non-recursive. */
|
|
1051
1218
|
private taskFiles;
|
|
1052
1219
|
private checkOneFile;
|
|
@@ -1116,7 +1283,7 @@ export declare class Daemon {
|
|
|
1116
1283
|
* log, and produces bytes only through `core/task-file.ts`. A file can no more
|
|
1117
1284
|
* teach the log a state than a screenshot can teach a database a row.
|
|
1118
1285
|
*
|
|
1119
|
-
*
|
|
1286
|
+
* Five rules, each of which is a way of not making things worse:
|
|
1120
1287
|
*
|
|
1121
1288
|
* 1. **Only files that already have an envelope.** `set-state` refuses
|
|
1122
1289
|
* `no-envelope`, and that refusal is honoured silently: a task with no
|
|
@@ -1138,6 +1305,11 @@ export declare class Daemon {
|
|
|
1138
1305
|
* envelope: each was warned about a few milliseconds ago by
|
|
1139
1306
|
* {@link scanForDrift} over the same folder. Repeating it here would double
|
|
1140
1307
|
* every line an operator reads without adding a fact.
|
|
1308
|
+
* 5. **No repair for a drift record that was deferred** (APRV-403). See the
|
|
1309
|
+
* check inside the loop: a file whose `envelope.drift` this tick could not
|
|
1310
|
+
* append is left exactly as it is, because repairing it would correct the
|
|
1311
|
+
* disagreement off the record and erase what the retry is supposed to
|
|
1312
|
+
* re-derive.
|
|
1141
1313
|
*
|
|
1142
1314
|
* Loop safety comes from the comparison, not from a remembered flag: the next
|
|
1143
1315
|
* tick derives the same state from the same log, finds the file already
|