@henols/vice-mcp 0.2.3 → 0.2.4

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.
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- // Container-side half of the on-demand broker protocol. Through Phase 01.2
3
- // this module wrote the request/lease files resources/vice-broker.sh read
4
- // and read the grant/denial/broker files that script wrote, all on the SAME
2
+ // Container-side half of the on-demand broker protocol. This module used to
3
+ // write the request/lease files resources/vice-broker.sh read and read the
4
+ // grant/denial/broker files that script wrote, all on the SAME
5
5
  // .vice-supervisor/ bind mount tools/vice-supervisor.sh's epoch.json already
6
- // used. Plan 01.6.2-07 deletes that file protocol wholesale (D-12: six
7
- // mechanisms retiring together -- startHeartbeat()/the mtime-as-heartbeat
6
+ // used. That whole file protocol is now deleted wholesale (six mechanisms
7
+ // retiring together -- startHeartbeat()/the mtime-as-heartbeat
8
8
  // convention/touchLease()/pollGrant()/pollRecycleAck()/the request-grant-
9
9
  // denial-lease-recycle-ack directory tree) now that vice-proxy.ts's
10
10
  // acquisition, release AND recycle all run over the TCP control plane
@@ -17,8 +17,8 @@
17
17
  //
18
18
  // Every read of broker.json is still untrusted input: parse in try/catch, a
19
19
  // malformed or half-written file is "not there yet" or "absent", never a
20
- // thrown exception. See 01.2-PATTERNS.md's "Never-throw /
21
- // never-cache-a-negative-result" section.
20
+ // thrown exception -- the never-throw, never-cache-a-negative-result
21
+ // posture this module holds throughout.
22
22
  //
23
23
  // MUST NOT import hostpath.ts: the host-path consumer set is closed to
24
24
  // exactly four production modules (containerpath.ts, install-resources.ts,
@@ -31,14 +31,15 @@ import { join, resolve } from "node:path";
31
31
  import { connect, type Socket } from "node:net";
32
32
 
33
33
  import { supervisorDir } from "./repo-root.ts";
34
- // Phase 33, plan 33-06 (D-15): TYPE-ONLY, and IMPORTED rather than
34
+ // TYPE-ONLY, and IMPORTED rather than
35
35
  // redeclared. broker-launch.mts is the one definition of the profile shape and
36
36
  // the module that turns a profile into argv; a second local shape here is how
37
37
  // a client would start requesting a knob the host cannot honour. Type-only, so
38
38
  // the container-side bundle never resolves the host-bound module at runtime.
39
39
  import type { LaunchProfile } from "./broker-launch.mts";
40
40
  // backend-detect.mts is ViceBackend's one home (narrowed to a single literal
41
- // by FORKRM-01, plan 52-06). Type-only, same discipline as the import above.
41
+ // now that the fork backend has been removed entirely). Type-only, same
42
+ // discipline as the import above.
42
43
  import type { ViceBackend } from "./backend-detect.mts";
43
44
  // The module tree's ONE definition of the container-visible host alias
44
45
  // (vice.ts:49), carrying its own VICE_MCP_HOST override -- consumed below by
@@ -57,8 +58,8 @@ import { mcpHost, ViceError } from "./vice-errors.ts";
57
58
 
58
59
  // -------------------------------------------------------------- request ids
59
60
  //
60
- // Primary noun of this protocol (assumption-delta decision, 01.2-01-PLAN.md):
61
- // a request/grant/lease is identified by this id, never by port -- ports are
61
+ // Primary noun of this protocol: a request/grant/lease is identified by
62
+ // this id, never by port -- ports are
62
63
  // recycled across sessions under on-demand launch, so a port is an attribute
63
64
  // OF a grant, not identity. Matched byte-for-byte against the same shape
64
65
  // resources/vice-broker.sh's own request-id pattern validates (T-01.2-01);
@@ -66,12 +67,10 @@ import { mcpHost, ViceError } from "./vice-errors.ts";
66
67
  // shared corpus through both validators so neither side can silently accept
67
68
  // an id shape the other rejects.
68
69
  //
69
- // C7 (Phase 01.6.1): this is the criterion's whole container-side
70
- // deliverable -- a real, typed, NAMED export whose VALUE is unchanged from
71
- // the pre-conversion .mjs (verified live, this plan's SUMMARY quotes both).
72
- // 01.6.2's in-process broker imports this exact binding rather than
73
- // re-stating the pattern a third time; the bash copy
74
- // (resources/vice-broker.sh) does not retire until that phase deletes it.
70
+ // This is a real, typed, NAMED export whose VALUE is unchanged from
71
+ // the pre-conversion .mjs (verified live). The in-process broker imports
72
+ // this exact binding rather than re-stating the pattern a third time; the
73
+ // bash copy (resources/vice-broker.sh) does not retire until it is deleted.
75
74
  export const REQUEST_ID_PATTERN: RegExp = /^req-[0-9]+-[0-9]+-[0-9a-f]{8}$/;
76
75
 
77
76
  export function newRequestId(): string {
@@ -91,8 +90,9 @@ export function isValidRequestId(id: unknown): id is string {
91
90
  // The five sibling directory helpers this function used to anchor
92
91
  // (requestsDir/grantsDir/denialsDir/brokerLeasesDir/recycleAcksDir) and the
93
92
  // lease path helper (leasePathFor) are GONE, not merely unused -- their
94
- // directories cease to exist under D-01/D-12; only brokerJsonPath() below
95
- // survives, since broker.json itself is not part of the retiring protocol.
93
+ // directories cease to exist now that the file protocol is retired; only
94
+ // brokerJsonPath() below survives, since broker.json itself is not part of
95
+ // the retiring protocol.
96
96
  export function brokerRootDir(): string {
97
97
  return process.env.VICE_POOL_DIR ? resolve(process.env.VICE_POOL_DIR) : supervisorDir();
98
98
  }
@@ -134,7 +134,7 @@ function readJsonMaybe(path: string): Record<string, unknown> | null {
134
134
  // writeRequest/createLease/touchLease/releaseLease/pollGrant/pollRecycleAck
135
135
  // and their record interfaces (RequestRecord, RecycleRequestRecord,
136
136
  // LeaseRecord, PollOptions, PollGrantResult, PollRecycleAckResult) are GONE:
137
- // the whole file-messaging protocol they implemented (D-01/D-12) is replaced
137
+ // the whole file-messaging protocol they implemented is replaced
138
138
  // wholesale by the TCP control plane below. GRANT_POLL_TIMEOUT_MS/
139
139
  // GRANT_POLL_INTERVAL_MS/RECYCLE_ACK_TIMEOUT_MS/RECYCLE_ACK_POLL_INTERVAL_MS
140
140
  // (the retiring polls' own timeout/interval constants) and sleepMs() (their
@@ -183,8 +183,8 @@ export function readBrokerLiveness(path: string = brokerJsonPath()): BrokerLiven
183
183
  }
184
184
 
185
185
  // StartHeartbeatOptions/HEARTBEAT_MS/startHeartbeat() are GONE -- the
186
- // lease-heartbeat interval (one of D-12's six retiring mechanisms) has no
187
- // successor. Nothing needs touching to prove a TCP connection is alive; it
186
+ // lease-heartbeat interval (one of the six retiring mechanisms named above)
187
+ // has no successor. Nothing needs touching to prove a TCP connection is alive; it
188
188
  // either is, or the broker's own "close" handler has already reclaimed the
189
189
  // instance.
190
190
 
@@ -300,9 +300,8 @@ export function resolveControlTarget(record: Record<string, unknown>, port: numb
300
300
  // ---------------------------------------------------- TCP control plane
301
301
  //
302
302
  // The container-side half of the TCP control plane (broker-control.mts is
303
- // the host-side half). Wire format confirmed at plan 01's blocking
304
- // checkpoint:decision (2026-08-03, `as-specified`; see
305
- // .planning/RE-FINDINGS.md for the full record): newline-delimited JSON,
303
+ // the host-side half). Wire format confirmed at an early blocking
304
+ // decision checkpoint (2026-08-03, `as-specified`): newline-delimited JSON,
306
305
  // per-boot capability token, connection open = claim / close = release.
307
306
  export interface AcquireGrant {
308
307
  id: string;
@@ -310,15 +309,16 @@ export interface AcquireGrant {
310
309
  url: string;
311
310
  epoch_file: string;
312
311
  supervisor_dir: string;
313
- /** Plan 41-01 (D-15); made mandatory-in-fact by plan 41-05 (D-16): the
314
- * broker-allocated port stock's `-remotemonitor` text monitor binds.
312
+ /** The broker-allocated port stock's `-remotemonitor` text monitor binds,
313
+ * mandatory in fact once a stock acquire without one was made to fail
314
+ * outright rather than degrade.
315
315
  * Absent on a fork grant only -- a stock grant that could not bind a
316
316
  * text-monitor port no longer reaches the wire at all: the acquire fails
317
317
  * outright (`no_free_text_port`) before any grant is produced. */
318
318
  remote_monitor_port?: number;
319
319
  }
320
320
 
321
- /** Plan 41-01: parses the wire's `remote_monitor_port` into a validated
321
+ /** Parses the wire's `remote_monitor_port` into a validated
322
322
  * integer in 1..65535, or `undefined` when the key is absent OR the observed
323
323
  * value is not a valid port -- never a fabricated 0/null standing in for
324
324
  * "no port", and never an unvalidated number handed downstream to a dial.
@@ -338,7 +338,7 @@ export interface AcquireOverControlPlaneHandle {
338
338
  release: () => void;
339
339
  }
340
340
 
341
- /** P-08 (01.6.2.1-04-PLAN.md): default raised from 25000 to 120000. The
341
+ /** Default raised from 25000 to 120000. The
342
342
  * knob (VICE_BROKER_ACQUIRE_TIMEOUT_MS) is unchanged -- an explicitly
343
343
  * configured value keeps working exactly as before.
344
344
  *
@@ -354,7 +354,7 @@ export interface AcquireOverControlPlaneHandle {
354
354
  * client's generic timeout. */
355
355
  export const CONTROL_ACQUIRE_TIMEOUT_MS: number = Number(process.env.VICE_BROKER_ACQUIRE_TIMEOUT_MS || 120000);
356
356
 
357
- /** Phase 33, plan 33-06 (REPRO-05, D-15): the request-side launch profile.
357
+ /** The request-side launch profile.
358
358
  * Optional and absent by default at BOTH acquire write sites in this file.
359
359
  *
360
360
  * ONE RULE, and it is the whole reason this shape is named rather than
@@ -373,17 +373,18 @@ export const CONTROL_ACQUIRE_TIMEOUT_MS: number = Number(process.env.VICE_BROKER
373
373
  * one of them silently never arrives for callers on the other path, which is
374
374
  * the same defect class as a tool argument that is accepted and dropped.
375
375
  *
376
- * CONSUMER STATUS: SUBSTRATE, NOT YET WIRED (33 review WR-08). The profile
376
+ * CONSUMER STATUS: SUBSTRATE, NOT YET WIRED. The profile
377
377
  * threads client -> wire -> narrowing -> eligibility -> argv -> record with
378
- * tests at every hop, but as of phase 33 NO production call site passes one:
378
+ * tests at every hop, but NO production call site passes one yet:
379
379
  * `acquireOverControlPlane()` and `BrokerControlSession.acquire()` are only
380
380
  * ever invoked without `opts.profile`, so `-warp` and `-console` are
381
- * unreachable in production. That is deliberate -- phase 33 built the chain
382
- * ahead of phases 34-38 using it -- and is recorded here rather than left for
383
- * a reader to discover, because a fully-tested chain reads as a live one.
381
+ * unreachable in production. That is deliberate -- the chain was built
382
+ * ahead of the callers that will use it -- and is recorded here rather than
383
+ * left for a reader to discover, because a fully-tested chain reads as a
384
+ * live one.
384
385
  *
385
386
  * Do NOT close this by inventing a call site. Note also that the profile is
386
- * refused outright on the fork backend (33 review WR-03, broker-control.mts):
387
+ * refused outright on the fork backend (broker-control.mts):
387
388
  * it maps to stock-only launch flags, so the first real consumer has to be on
388
389
  * stock. */
389
390
  export interface AcquireProfileOptions {
@@ -405,7 +406,7 @@ function acquireProfileFragment(profile?: LaunchProfile): { profile?: LaunchProf
405
406
  * failure: broker.json absent/unreadable/missing the control fields, a
406
407
  * connection error, an `error` response, or a timeout.
407
408
  *
408
- * Phase 33, plan 33-06: takes an optional `profile` (see
409
+ * Additionally takes an optional `profile` (see
409
410
  * AcquireProfileOptions above). Omitting it writes the exact wire line this
410
411
  * function has always written. */
411
412
  export function acquireOverControlPlane(dir: string = brokerRootDir(), opts: AcquireProfileOptions = {}): Promise<AcquireOverControlPlaneHandle> {
@@ -444,7 +445,7 @@ export function acquireOverControlPlane(dir: string = brokerRootDir(), opts: Acq
444
445
 
445
446
  socket.on("connect", () => {
446
447
  const requestId = newRequestId();
447
- // Phase 33, plan 33-06: write site ONE of two (see
448
+ // Write site ONE of two (see
448
449
  // acquireProfileFragment()'s own comment) -- the key is absent entirely
449
450
  // when no profile was requested, so this line stays byte-identical to
450
451
  // what it always was for a profile-less acquire.
@@ -514,16 +515,16 @@ export function acquireOverControlPlane(dir: string = brokerRootDir(), opts: Acq
514
515
  }
515
516
 
516
517
  // ---------------------------------------------------------------------------
517
- // BROKER-CONTROL-CLIENT REGION START (plan 06, task 1)
518
+ // BROKER-CONTROL-CLIENT REGION START
518
519
  //
519
- // Completed by plan 07 (the file protocol beside it is now gone).
520
- // openBrokerControl() is the container-side half of D-01: session shape,
521
- // all five request kinds, one discovery-record read, real per-request
522
- // deadlines, and a distinct broker-gone outcome. Lives alongside
523
- // acquireOverControlPlane() above (plan 01's tracer, kept unchanged and
520
+ // The file protocol beside it is now gone.
521
+ // openBrokerControl() is the container-side half of the TCP control plane:
522
+ // session shape, all five request kinds, one discovery-record read, real
523
+ // per-request deadlines, and a distinct broker-gone outcome. Lives alongside
524
+ // acquireOverControlPlane() above (an early tracer, kept unchanged and
524
525
  // still used by broker-e2e.test.ts/broker-kill.test.ts as their own one-shot
525
526
  // acquire helper for exercising the SERVER side) -- the file protocol this
526
- // region's own predecessor sat beside is gone (plan 07, D-12).
527
+ // region's own predecessor sat beside is gone entirely.
527
528
  //
528
529
  // Deliberately never REJECTS a promise: every failure -- deadline, a
529
530
  // refused connection, a malformed line, the broker going away mid-request --
@@ -541,21 +542,19 @@ export function acquireOverControlPlane(dir: string = brokerRootDir(), opts: Acq
541
542
 
542
543
  /** Same value as the tracer's own CONTROL_ACQUIRE_TIMEOUT_MS above --
543
544
  * referenced directly (not re-computed from the env var a second time) so
544
- * the two can never drift apart. This is "the relocated value of the
545
- * retiring grant-poll timeout" per 01.6.2-01-PLAN.md's own environment
546
- * variable table (VICE_BROKER_ACQUIRE_TIMEOUT_MS, default now 120000, raised
547
- * from 25000 per P-08 / 01.6.2.1-04-PLAN.md, against the measured tool-call
545
+ * the two can never drift apart. This is the relocated value of the
546
+ * retiring grant-poll timeout (VICE_BROKER_ACQUIRE_TIMEOUT_MS, default now
547
+ * 120000, raised from 25000 against the measured tool-call
548
548
  * budget spike-003 established -- see the counter-evidence comment at
549
549
  * CONTROL_ACQUIRE_TIMEOUT_MS's own declaration above). */
550
550
  export const ACQUIRE_TIMEOUT_MS: number = CONTROL_ACQUIRE_TIMEOUT_MS;
551
551
 
552
- /** The recycle bound. Plan 06 referenced the (now-deleted) retiring
553
- * pollRecycleAck()'s own RECYCLE_ACK_TIMEOUT_MS directly, so the two could
554
- * never drift apart while both existed; that predecessor is gone (plan 07,
555
- * D-12), so this reads the SAME environment variable directly -- the value
556
- * itself is unchanged (VICE_BROKER_RECYCLE_TIMEOUT_MS, default 30000, per
557
- * 01.6.2-01-PLAN.md's own environment variable table). Final tuning is
558
- * Phase 01.6.2.1's item. */
552
+ /** The recycle bound. An earlier revision referenced the (now-deleted)
553
+ * retiring pollRecycleAck()'s own RECYCLE_ACK_TIMEOUT_MS directly, so the
554
+ * two could never drift apart while both existed; that predecessor is gone
555
+ * entirely, so this reads the SAME environment variable directly -- the
556
+ * value itself is unchanged (VICE_BROKER_RECYCLE_TIMEOUT_MS, default
557
+ * 30000). Final tuning remains a future item. */
559
558
  export const RECYCLE_TIMEOUT_MS: number = Number(process.env.VICE_BROKER_RECYCLE_TIMEOUT_MS || 30000);
560
559
 
561
560
  /** Genuinely NEW: the file protocol never "connected" anywhere, so there is
@@ -563,9 +562,9 @@ export const RECYCLE_TIMEOUT_MS: number = Number(process.env.VICE_BROKER_RECYCLE
563
562
  * a TCP connect over the docker bridge to a broker broker.json has already
564
563
  * classified alive (never_started/stale are refused before a connection is
565
564
  * ever attempted) -- deliberately not read from an environment variable,
566
- * since 01.6.2-06-PLAN.md's own scope is "no new environment variables
567
- * beyond the two deadline variables named in 01.6.2-01-PLAN.md" (the two
568
- * above). Final tuning is Phase 01.6.2.1's item, same as the other two. */
565
+ * since no new environment variable was wanted beyond the two deadline
566
+ * variables named above. Final tuning remains a future item, same as the
567
+ * other two. */
569
568
  export const CONTROL_CONNECT_TIMEOUT_MS = 5000;
570
569
 
571
570
  /** Every way a session-level request can fail to produce its expected
@@ -592,7 +591,7 @@ export type ControlFailureKind =
592
591
  | "no_free_port"
593
592
  | "at_capacity"
594
593
  | "internal"
595
- // Plan 05 (BROK-02/PROTO-08): the broker's own ControlErrorCode gained
594
+ // The broker's own ControlErrorCode gained
596
595
  // this member for the ownership-conflict outcome; duplicated here for the
597
596
  // same reason every other member already is (this client and the broker
598
597
  // run in separate processes -- the shared surface is the wire format, not
@@ -631,7 +630,7 @@ interface ControlHostStateFields {
631
630
  warm_floor: number;
632
631
  max_instances: number;
633
632
  base_port: number;
634
- /** FORKRM-01 (plan 52-06): narrowed from `"fork" | "stock" | null` to
633
+ /** Narrowed from `"fork" | "stock" | null` to
635
634
  * `ViceBackend | null` -- `null` when the broker predates this field or
636
635
  * sent something unrecognised: absent evidence, kept distinct from a
637
636
  * definite value. text-tools.ts's own broker-identity cross-check (out of
@@ -644,7 +643,7 @@ export type ControlHostStateResult =
644
643
  | { ok: false; kind: ControlFailureKind; message: string };
645
644
 
646
645
  // ---------------------------------------------------------------------------
647
- // MonitorClaimChannel (plan 41-03, D-14): the two-value channel contract,
646
+ // MonitorClaimChannel: the two-value channel contract,
648
647
  // declared HERE as a local literal union rather than imported from
649
648
  // broker-state.mts -- that module is host-bound and compiled into
650
649
  // resources/*.mjs, and this file is the container-side half. The shared
@@ -655,9 +654,8 @@ export type ControlHostStateResult =
655
654
  // ---------------------------------------------------------------------------
656
655
  export type MonitorClaimChannel = "binary" | "text";
657
656
 
658
- /** Plan 05 (BROK-02/PROTO-08, D-13; gains `channel` in plan 41-03, D-14): the
659
- * current monitor-socket holder's own identity, named in a `monitor_owned`
660
- * refusal -- field-for-field the same shape the broker's own MonitorHolder
657
+ /** The current monitor-socket holder's own identity, named in a
658
+ * `monitor_owned` refusal -- field-for-field the same shape the broker's own MonitorHolder
661
659
  * carries (broker-control.mts), minus nothing (pid included, matching
662
660
  * GrantRecord's own convention this whole mechanism mirrors). */
663
661
  export interface MonitorClaimHolder {
@@ -670,8 +668,8 @@ export interface MonitorClaimHolder {
670
668
  export interface ClaimMonitorOptions {
671
669
  targetId: string;
672
670
  timeoutMs?: number;
673
- /** Plan 41-03 (D-14): which monitor socket to claim. Omitted is
674
- * byte-identical to `"binary"` -- every pre-41-03 call site (and every
671
+ /** Which monitor socket to claim. Omitted is
672
+ * byte-identical to `"binary"` -- every pre-existing call site (and every
675
673
  * broker that predates this field) keeps working unchanged. */
676
674
  channel?: MonitorClaimChannel;
677
675
  }
@@ -679,20 +677,20 @@ export interface ClaimMonitorOptions {
679
677
  export interface ReleaseMonitorOptions {
680
678
  targetId: string;
681
679
  timeoutMs?: number;
682
- /** Plan 41-03 (D-14): same default-to-binary posture as ClaimMonitorOptions.channel. */
680
+ /** Same default-to-binary posture as ClaimMonitorOptions.channel. */
683
681
  channel?: MonitorClaimChannel;
684
682
  }
685
683
 
686
- /** Discriminated claim outcome (plan 05): `monitor_owned` is kept STRICTLY
684
+ /** Discriminated claim outcome: `monitor_owned` is kept STRICTLY
687
685
  * separate from `timeout` -- conflating "someone else holds it" with "the
688
- * broker did not answer" would reintroduce exactly the ambiguity PROTO-08
689
- * exists to remove. Never thrown; a caller that wants to raise instead
686
+ * broker did not answer" would reintroduce exactly the ambiguity this
687
+ * distinction exists to remove. Never thrown; a caller that wants to raise instead
690
688
  * should construct a MonitorOwnershipError from this outcome's own fields
691
689
  * (see that class's own header comment). */
692
690
  export type ClaimMonitorOutcome =
693
691
  | { ok: true }
694
692
  | { ok: false; reason: "monitor_owned"; holder: MonitorClaimHolder }
695
- // "denied" (CR-03): the broker's control plane refused because the grant
693
+ // "denied": the broker's control plane refused because the grant
696
694
  // named is not the one THIS connection holds. In a correct client that is
697
695
  // unreachable -- stockConnect() always claims the grant its own session
698
696
  // acquired -- so it is carried as its own reason rather than collapsed into
@@ -707,15 +705,15 @@ export interface MonitorOwnershipErrorOptions {
707
705
  holderGrantId?: string;
708
706
  holderClaimedAt?: number;
709
707
  port?: number;
710
- /** Plan 41-03 (D-14): which socket is contended -- so a handshake failure
708
+ /** Which socket is contended -- so a handshake failure
711
709
  * can say which channel was refused without re-parsing the message. */
712
710
  channel?: MonitorClaimChannel;
713
711
  }
714
712
 
715
713
  /** Thrown (by a caller that prefers to raise rather than branch on
716
714
  * ClaimMonitorOutcome) when `monitor_claim` is refused because a DIFFERENT
717
- * grant already holds this instance's monitor socket (plan 05, PROTO-08,
718
- * D-13). Names the holding grant and the port plainly, as an ownership
715
+ * grant already holds this instance's monitor socket. Names the holding
716
+ * grant and the port plainly, as an ownership
719
717
  * conflict -- a state the broker itself enforced, distinct from an emulator
720
718
  * that has stopped answering, and NOT a state the vice-wedge-triage skill's
721
719
  * opening move should ever be misdirected by.
@@ -724,9 +722,9 @@ export interface MonitorOwnershipErrorOptions {
724
722
  * connect() is ever attempted: stock VICE services exactly one binmon
725
723
  * client, and a second connect() produces no reply and no EOF, so a refusal
726
724
  * arriving only after dialling would be byte-for-byte indistinguishable
727
- * from a wedge (PROTO-08). Claiming first means this refusal is a JSON
725
+ * from a wedge. Claiming first means this refusal is a JSON
728
726
  * response on a control-plane socket that already works, and the second
729
- * client never dials the binmon port at all (D-13). */
727
+ * client never dials the binmon port at all. */
730
728
  export class MonitorOwnershipError extends ViceError {
731
729
  holderGrantId?: string;
732
730
  holderClaimedAt?: number;
@@ -759,16 +757,16 @@ export interface ControlDeadlineOptions {
759
757
  * exactly one request line and resolves against its own deadline; none of
760
758
  * them ever reject. */
761
759
  export interface BrokerControlSession {
762
- /** Phase 33, plan 33-06 (REPRO-05, D-15): additionally takes an optional
760
+ /** Additionally takes an optional
763
761
  * `profile` -- see AcquireProfileOptions. Omitting it is byte-identical to
764
- * every pre-33-06 call. */
762
+ * every pre-existing call. */
765
763
  acquire(opts?: ControlDeadlineOptions & AcquireProfileOptions): Promise<ControlAcquireResult>;
766
764
  release(): Promise<ControlReleaseResult>;
767
765
  recycle(targetId: string, opts?: ControlDeadlineOptions): Promise<ControlRecycleResult>;
768
766
  status(opts?: ControlDeadlineOptions): Promise<ControlStatusResult>;
769
767
  hostState(opts?: ControlDeadlineOptions): Promise<ControlHostStateResult>;
770
768
  /** Claims exclusive ownership of an instance's monitor socket BEFORE any
771
- * binmon connect() is attempted (plan 05, PROTO-08, D-13) -- see
769
+ * binmon connect() is attempted -- see
772
770
  * MonitorOwnershipError's own header comment for why claiming first is
773
771
  * the only way this refusal can ever be distinguishable from a wedge. */
774
772
  claimMonitor(opts: ClaimMonitorOptions): Promise<ClaimMonitorOutcome>;
@@ -788,7 +786,7 @@ export type OpenBrokerControlOutcome =
788
786
 
789
787
  /** The backend-agnostic coordinate set a session which ALREADY holds a
790
788
  * broker grant hands to anything that needs to dial the instance that grant
791
- * names (plan 02-09, PROTO-08, D-13). Declared here, beside
789
+ * names. Declared here, beside
792
790
  * BrokerControlSession and openBrokerControl(), because it is
793
791
  * backend-agnostic -- the fork path does not consume it only because
794
792
  * forwardToVice() reads activeInstance() from the same module (vice.ts)
@@ -806,7 +804,7 @@ export interface HeldLease {
806
804
  port: number;
807
805
  targetId: string;
808
806
  brokerControl: BrokerControlSession;
809
- /** CR-06: THIS instance's own epoch.json, in the CONSUMER's view of the
807
+ /** THIS instance's own epoch.json, in the CONSUMER's view of the
810
808
  * filesystem (i.e. already containerized -- vice-proxy.ts fills it from
811
809
  * activeInstance().epochFile, which adoptGrant() set from the containerized
812
810
  * grant). This is the reconnect-identity baseline stock-connect.ts's
@@ -817,7 +815,7 @@ export interface HeldLease {
817
815
  * Empty string means genuinely no epoch evidence exists, which is that same
818
816
  * unprovable case stated explicitly rather than by omission. */
819
817
  epochFile: string;
820
- /** CR-06: the TOP-LEVEL supervisor directory -- the one holding
818
+ /** The TOP-LEVEL supervisor directory -- the one holding
821
819
  * `backend.json`, i.e. the same directory `broker.json` is read from
822
820
  * (brokerRootDir()). Deliberately NOT the grant's own per-instance
823
821
  * `supervisor_dir` (`<stateDir>/<port>`), which holds epoch.json and would
@@ -827,7 +825,7 @@ export interface HeldLease {
827
825
  * backend-detect.mts's own documented degradation for an omitted
828
826
  * supervisorDir. */
829
827
  supervisorDir: string;
830
- /** Plan 41-01 (D-15); made mandatory-in-fact by plan 41-05 (D-16): THIS
828
+ /** THIS
831
829
  * instance's own text-monitor port, read by text-connect.ts's
832
830
  * textConnect() to dial the `-remotemonitor` channel. MANDATORY on a
833
831
  * stock grant, ABSENT on a fork grant -- the fork never launches with
@@ -868,9 +866,9 @@ type RawLineOutcome = { ok: true; line: Record<string, unknown> } | { ok: false;
868
866
 
869
867
  /** Never-throw extraction of a `holder` payload from untrusted wire input --
870
868
  * absent or malformed input answers `undefined`, never a partially-filled
871
- * object (plan 05's own never-throw-on-untrusted-input posture, matching
872
- * this file's own header comment on broker.json reads). `channel` (plan
873
- * 41-03, D-14) defaults to `requestedChannel` -- THE channel this request
869
+ * object (this module's own never-throw-on-untrusted-input posture, matching
870
+ * this file's own header comment on broker.json reads). `channel`
871
+ * defaults to `requestedChannel` -- THE channel this request
874
872
  * itself named -- when the wire omits it or sends something unrecognised;
875
873
  * never fabricated as a plausible value, in the same register the
876
874
  * `grantId: "unknown"` fallback one layer up (claimMonitor()'s own) uses. */
@@ -960,10 +958,10 @@ function createSession(socket: Socket, token: string): BrokerControlSession {
960
958
  }
961
959
  if (line.kind === "error") {
962
960
  const code = typeof line.code === "string" ? (line.code as ControlFailureKind) : "internal";
963
- // Plan 05: forward `holder` verbatim ONLY for monitor_owned --
961
+ // Forward `holder` verbatim ONLY for monitor_owned --
964
962
  // every other error code carries no such field on the wire, and
965
963
  // extractHolder() itself never invents one from absent/malformed
966
- // input. Plan 41-03 (D-14): the requested channel comes from
964
+ // input. The requested channel comes from
967
965
  // THIS payload (the request this response answers), read from
968
966
  // the same closure `payload` sendAndAwaitLine() was called
969
967
  // with -- an absent/malformed wire `channel` is never fabricated,
@@ -997,7 +995,7 @@ function createSession(socket: Socket, token: string): BrokerControlSession {
997
995
 
998
996
  async function acquire(opts: ControlDeadlineOptions & AcquireProfileOptions = {}): Promise<ControlAcquireResult> {
999
997
  const requestId = newRequestId();
1000
- // Phase 33, plan 33-06: write site TWO of two (see
998
+ // Write site TWO of two (see
1001
999
  // acquireProfileFragment()'s own comment for why both matter) -- same
1002
1000
  // key-omitted-when-absent discipline as acquireOverControlPlane()'s raw
1003
1001
  // socket.write above.
@@ -1060,7 +1058,7 @@ function createSession(socket: Socket, token: string): BrokerControlSession {
1060
1058
  // in-memory read on the broker side (no launch, no kill involved), so it
1061
1059
  // needs no timeout of its own scale; introducing a distinct constant (or
1062
1060
  // environment variable) for it would be exactly the kind of new knob
1063
- // 01.6.2-06-PLAN.md's own scope excludes.
1061
+ // this module deliberately declines to add.
1064
1062
  const raw = await sendAndAwaitLine({ op: "status", token }, opts.timeoutMs ?? ACQUIRE_TIMEOUT_MS);
1065
1063
  if (!raw.ok) return raw;
1066
1064
  const line = raw.line;
@@ -1099,7 +1097,7 @@ function createSession(socket: Socket, token: string): BrokerControlSession {
1099
1097
  warm_floor: Number(line.warm_floor),
1100
1098
  max_instances: Number(line.max_instances),
1101
1099
  base_port: Number(line.base_port),
1102
- // FORKRM-01 (plan 52-06): narrowed at the boundary, never cast --
1100
+ // Narrowed at the boundary, never cast --
1103
1101
  // anything other than the one known verdict reads as `null` ("this
1104
1102
  // broker did not tell us"), which callers must treat as absent
1105
1103
  // evidence rather than agreement.
@@ -1113,19 +1111,19 @@ function createSession(socket: Socket, token: string): BrokerControlSession {
1113
1111
  * `sendAndAwaitLine()` path -- the same session, the same token, the same
1114
1112
  * newline-delimited JSON discipline every other op uses; no second
1115
1113
  * control connection is ever opened, and this function never dials the
1116
- * binmon port itself, on success OR on failure (plan 05, PROTO-08, D-13
1117
- * -- see MonitorOwnershipError's own header comment for why the claim is
1118
- * made BEFORE any binmon connect()). `timeout` is reported distinctly
1114
+ * binmon port itself, on success OR on failure -- see
1115
+ * MonitorOwnershipError's own header comment for why the claim is
1116
+ * made BEFORE any binmon connect(). `timeout` is reported distinctly
1119
1117
  * from `monitor_owned`: a timeout means the broker did not answer, never
1120
- * that someone else owns the socket. `channel` (plan 41-03, D-14) defaults
1121
- * to `"binary"` when omitted -- byte-identical to every pre-41-03 call. */
1118
+ * that someone else owns the socket. `channel` defaults
1119
+ * to `"binary"` when omitted -- byte-identical to every pre-existing call. */
1122
1120
  async function claimMonitor(opts: ClaimMonitorOptions): Promise<ClaimMonitorOutcome> {
1123
1121
  const requestId = newRequestId();
1124
1122
  const channel: MonitorClaimChannel = opts.channel ?? "binary";
1125
1123
  const raw = await sendAndAwaitLine({ op: "monitor_claim", id: requestId, target_id: opts.targetId, channel, token }, opts.timeoutMs ?? ACQUIRE_TIMEOUT_MS);
1126
1124
  if (!raw.ok) {
1127
1125
  if (raw.kind === "deadline") return { ok: false, reason: "timeout" };
1128
- // WR-08: the `monitor_owned` REASON survives even when the wire's own
1126
+ // The `monitor_owned` REASON survives even when the wire's own
1129
1127
  // `holder` payload is absent or malformed. This used to be
1130
1128
  // `raw.kind === "monitor_owned" && raw.holder`, so a partially-malformed
1131
1129
  // refusal collapsed to `{ ok: false, reason: "internal" }` -- stockConnect()
@@ -1154,7 +1152,7 @@ function createSession(socket: Socket, token: string): BrokerControlSession {
1154
1152
  * session. Tolerates a broker that has already cleared the record (the
1155
1153
  * broker's own onMonitorRelease answers `ok: true` for an already-cleared
1156
1154
  * target) -- this function never retries and never opens a second
1157
- * connection. `channel` (plan 41-03, D-14) defaults to `"binary"` when
1155
+ * connection. `channel` defaults to `"binary"` when
1158
1156
  * omitted. */
1159
1157
  async function releaseMonitor(opts: ReleaseMonitorOptions): Promise<ReleaseMonitorOutcome> {
1160
1158
  const requestId = newRequestId();
@@ -1268,5 +1266,5 @@ export function openBrokerControl(dir: string = brokerRootDir(), opts: OpenBroke
1268
1266
  }
1269
1267
 
1270
1268
  // ---------------------------------------------------------------------------
1271
- // BROKER-CONTROL-CLIENT REGION END (plan 06, task 1)
1269
+ // BROKER-CONTROL-CLIENT REGION END
1272
1270
  // ---------------------------------------------------------------------------