@eir-labs/coltrane 0.24.35 → 0.24.36

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/dist/src/cli.d.ts CHANGED
@@ -34,7 +34,7 @@ export interface CliIO {
34
34
  * every other command reads process.env directly, and moving them is not this change's scope. */
35
35
  env?: Record<string, string | undefined>;
36
36
  }
37
- export declare const USAGE = "coltrane 0.24.35\n\n coltrane validate load the genome; exit non-zero on load errors OR on an\n orphan \u2014 a standards/|domain_types/|agents/ file with no\n genome_mutation seal in the tracked genome ledger\n coltrane seal-genome [<genome_dir>] bulk-seal a pre-sealing genome: append a genome_mutation\n seal for every standards/|domain_types/|agents/ file not yet\n sealed, via the blessed sealDefinition path. Content is\n byte-unchanged; a second run seals nothing already sealed.\n (default genome_dir: cwd)\n coltrane dispatch <standard> run a standard\n coltrane monitor <gig-id> report a gig's progress\n coltrane logs <gig-id> per-chair logs for a gig\n coltrane abort <gig-id> stop a running gig\n coltrane trace <output-id> walk an output's provenance\n coltrane simulate <standard> cost/shape a standard without running it\n coltrane health engine + store health\n coltrane serve run the MCP server on stdio\n coltrane enqueue <standard> queue a gig on the LOCAL file queue (no store, no key)\n (env: COLTRANE_QUEUE_DIR \u2014 its absence is the whole\n difference between local and hosted)\n coltrane work claim one queued gig from the org store and run it\n coltrane work --check report whether this box's drain environment is configured\n and exit without claiming (0 ready, 1 not ready)\n (env: COLTRANE_STORE_URL, COLTRANE_STORE_ANON,\n COLTRANE_AGENT_TOKEN; results drain via\n COLTRANE_DRAIN_URL + COLTRANE_DRAIN_KEY;\n checkpoints under COLTRANE_WORKER_CHECKPOINTS,\n default ~/.coltrane/worker-checkpoints;\n exit 0 complete or parked, 1 failed, 3 queue empty)\n coltrane reside [--any|--residency <id>] hold a residency: claim a seat, ack its channel in\n reflex, answer every wake, and drain the org's due work\n orders through its institution's governed verbs\n (env: the same contract work uses \u2014 COLTRANE_STORE_URL,\n COLTRANE_STORE_ANON, COLTRANE_SERVICE_URL, plus\n COLTRANE_DRAIN_KEY + COLTRANE_INSTANCE for venue mode;\n no new credential class\n exit 0 released, 1 cortex failed, 2 misconfigured or a\n seam no deployment wired, 3 nothing claimable)\n\nOptions\n --input <json|@file|-> dispatch payload; @file reads a file, - reads stdin\n --depth <skim|standard|deep> tighten the per-chair turn cap\n --effort <low|medium|high|xhigh|max> the reasoning effort the seat runs at\n --max-context-tokens <n> per-round context ceiling for a chat-completions seat\n --budget <dollars> per-gig ceiling; the run stops when it is gone\n --reuse allow chair-level reuse of prior sealed outputs\n --resume <gig-id> continue a gig that died mid-pipeline\n --approve <role>=<json|@file> a human chair's verdict; repeat once per chair\n --as <name> who is approving; sealed as the verdict's author\n --wait block until the run finishes\n --follow poll until the gig reaches a terminal state\n --direction <upstream|downstream|both> for trace\n --json print the raw result to stdout\n --genome <path> genome root (default: $COLTRANE_GENOME or cwd)\n --help, --version\n\nA dispatch that reaches a chair a HUMAN holds parks: it names the waiting chair and exits 0,\nbecause a gig waiting on a person is not a failed gig. Approve it on the resume \u2014\n\n coltrane dispatch <standard> --resume <gig> \\\n --approve approve=@verdict.json --as eugene\n\n--input is NOT required on an approve-only resume: when every remaining chair is human the\ncheckpoint's recorded payload stands and the omission inherits it. If you DO pass --input it is\nchecked against the checkpoint, and a disagreement still refuses the resume.\n";
37
+ export declare const USAGE = "coltrane 0.24.36\n\n coltrane validate load the genome; exit non-zero on load errors OR on an\n orphan \u2014 a standards/|domain_types/|agents/ file with no\n genome_mutation seal in the tracked genome ledger\n coltrane seal-genome [<genome_dir>] bulk-seal a pre-sealing genome: append a genome_mutation\n seal for every standards/|domain_types/|agents/ file not yet\n sealed, via the blessed sealDefinition path. Content is\n byte-unchanged; a second run seals nothing already sealed.\n (default genome_dir: cwd)\n coltrane dispatch <standard> run a standard\n coltrane monitor <gig-id> report a gig's progress\n coltrane logs <gig-id> per-chair logs for a gig\n coltrane abort <gig-id> stop a running gig\n coltrane trace <output-id> walk an output's provenance\n coltrane simulate <standard> cost/shape a standard without running it\n coltrane health engine + store health\n coltrane serve run the MCP server on stdio\n coltrane enqueue <standard> queue a gig on the LOCAL file queue (no store, no key)\n (env: COLTRANE_QUEUE_DIR \u2014 its absence is the whole\n difference between local and hosted)\n coltrane work claim one queued gig from the org store and run it\n coltrane work --check report whether this box's drain environment is configured\n and exit without claiming (0 ready, 1 not ready)\n (env: COLTRANE_STORE_URL, COLTRANE_STORE_ANON,\n COLTRANE_AGENT_TOKEN; results drain via\n COLTRANE_DRAIN_URL + COLTRANE_DRAIN_KEY;\n checkpoints under COLTRANE_WORKER_CHECKPOINTS,\n default ~/.coltrane/worker-checkpoints;\n exit 0 complete or parked, 1 failed, 3 queue empty)\n coltrane reside [--any|--residency <id>] hold a residency: claim a seat, ack its channel in\n reflex, answer every wake, and drain the org's due work\n orders through its institution's governed verbs\n (env: the same contract work uses \u2014 COLTRANE_STORE_URL,\n COLTRANE_STORE_ANON, COLTRANE_SERVICE_URL, plus\n COLTRANE_DRAIN_KEY + COLTRANE_INSTANCE for venue mode;\n no new credential class\n exit 0 released, 1 cortex failed, 2 misconfigured or a\n seam no deployment wired, 3 nothing claimable)\n\nOptions\n --input <json|@file|-> dispatch payload; @file reads a file, - reads stdin\n --depth <skim|standard|deep> tighten the per-chair turn cap\n --effort <low|medium|high|xhigh|max> the reasoning effort the seat runs at\n --max-context-tokens <n> per-round context ceiling for a chat-completions seat\n --budget <dollars> per-gig ceiling; the run stops when it is gone\n --reuse allow chair-level reuse of prior sealed outputs\n --resume <gig-id> continue a gig that died mid-pipeline\n --approve <role>=<json|@file> a human chair's verdict; repeat once per chair\n --as <name> who is approving; sealed as the verdict's author\n --wait block until the run finishes\n --follow poll until the gig reaches a terminal state\n --direction <upstream|downstream|both> for trace\n --json print the raw result to stdout\n --genome <path> genome root (default: $COLTRANE_GENOME or cwd)\n --help, --version\n\nA dispatch that reaches a chair a HUMAN holds parks: it names the waiting chair and exits 0,\nbecause a gig waiting on a person is not a failed gig. Approve it on the resume \u2014\n\n coltrane dispatch <standard> --resume <gig> \\\n --approve approve=@verdict.json --as eugene\n\n--input is NOT required on an approve-only resume: when every remaining chair is human the\ncheckpoint's recorded payload stands and the omission inherits it. If you DO pass --input it is\nchecked against the checkpoint, and a disagreement still refuses the resume.\n";
38
38
  interface Parsed {
39
39
  cmd: string | undefined;
40
40
  positional: string[];
@@ -870,5 +870,21 @@ export declare function genomeHash(standard: Standard): string;
870
870
  * source movement's sealed records does an edge of type T carry — and two layers answering "does
871
871
  * this record satisfy this declared type" differently is the #263 defect wearing a new hat. */
872
872
  export declare function outputSatisfiesType(output: OutputRecord, declared: string): boolean;
873
+ /** The near-miss refusal message. BOTH doors call this so the refusal reads identically down to the
874
+ * character, whichever door caught it — the preflight throws it inside a RuntimeError, the hosted door
875
+ * returns it as a typed JSON refusal. */
876
+ export declare function unknownGigInputMessage(offendingKey: string, declaredKey: string, standardSlug: string): string;
877
+ /** Partition a dispatch payload's keys against a standard's declared inputs, exactly as the preflight
878
+ * does. A key that is not declared but NORMALIZES to a declared key which is ALSO present is a NEAR
879
+ * MISS (the first one found is returned; the caller refuses on it). Every OTHER undeclared key is an
880
+ * EXTRA, returned sorted. A refused near-miss is never also an extra. `isPresent` answers whether a
881
+ * declared key carries a value in the payload — the collision only bites when both spellings are present. */
882
+ export declare function partitionGigInputKeys(payloadKeys: readonly string[], declaredInputs: readonly string[], isPresent: (declaredKey: string) => boolean): {
883
+ nearMiss?: {
884
+ key: string;
885
+ declaredKey: string;
886
+ };
887
+ extras: string[];
888
+ };
873
889
  export declare function runGig(standard: Standard, gigInput: Record<string, unknown>, deps: RunDeps): Promise<GigResult>;
874
890
  export {};
@@ -388,6 +388,39 @@ export function outputSatisfiesType(output, declared) {
388
388
  return true;
389
389
  return false;
390
390
  }
391
+ // contract-unknown-gig-input-v1 / contract-post-time-gig-input-v1 — the near-miss vocabulary, shared.
392
+ // The LOCAL preflight (below, in runGig) and the HOSTED dispatch door (src/server.ts) partition the
393
+ // same payload against the same declared inputs; extracting the partition and its message here is what
394
+ // makes the two doors identical BY CONSTRUCTION rather than by two copies drifting apart (O2).
395
+ /** Normalize a gig-input key for near-miss detection: case, hyphens, underscores and spaces removed,
396
+ * so `grant_requirements` and `grant-requirements` collapse to one string. Byte-for-byte the regex the
397
+ * preflight's `missingGigInput` hint uses, so the two never disagree about what "resembles" means. */
398
+ const normalizeGigInputKey = (k) => k.toLowerCase().replace(/[_\-\s]/g, "");
399
+ /** The near-miss refusal message. BOTH doors call this so the refusal reads identically down to the
400
+ * character, whichever door caught it — the preflight throws it inside a RuntimeError, the hosted door
401
+ * returns it as a typed JSON refusal. */
402
+ export function unknownGigInputMessage(offendingKey, declaredKey, standardSlug) {
403
+ return `dispatch payload key "${offendingKey}" is not declared by standard "${standardSlug}", but normalizes to declared gig input "${declaredKey}", which is ALSO present — one of the two spellings is being dropped and the caller cannot see which. Gig input keys are the hyphenated type slug, so rename "${offendingKey}" to "${declaredKey}" or drop it.`;
404
+ }
405
+ /** Partition a dispatch payload's keys against a standard's declared inputs, exactly as the preflight
406
+ * does. A key that is not declared but NORMALIZES to a declared key which is ALSO present is a NEAR
407
+ * MISS (the first one found is returned; the caller refuses on it). Every OTHER undeclared key is an
408
+ * EXTRA, returned sorted. A refused near-miss is never also an extra. `isPresent` answers whether a
409
+ * declared key carries a value in the payload — the collision only bites when both spellings are present. */
410
+ export function partitionGigInputKeys(payloadKeys, declaredInputs, isPresent) {
411
+ const declaredSet = new Set(declaredInputs);
412
+ const declaredPresent = declaredInputs.filter((d) => isPresent(d));
413
+ const extras = [];
414
+ for (const key of payloadKeys) {
415
+ if (declaredSet.has(key))
416
+ continue; // a declared key is read, never undeclared
417
+ const declaredKey = declaredPresent.find((d) => normalizeGigInputKey(d) === normalizeGigInputKey(key));
418
+ if (declaredKey !== undefined)
419
+ return { nearMiss: { key, declaredKey }, extras: [] };
420
+ extras.push(key);
421
+ }
422
+ return { extras: extras.sort() };
423
+ }
391
424
  export async function runGig(standard, gigInput, deps) {
392
425
  // A resumed run CONTINUES the gig it resumes: same id, so the restored outputs stay in-gig
393
426
  // and `OutputStore.trace` (which scopes its walk to one gig_id) still reaches them. Two ids
@@ -715,24 +748,22 @@ export async function runGig(standard, gigInput, deps) {
715
748
  // them sorted, never refused (harmless metadata keeps the gig running). A refused near-miss is
716
749
  // never in `extras`, so it is never also reported as an extra (F1 — never twice for one key).
717
750
  {
718
- const declaredPresent = [...standardInputs].filter((d) => gigInput[d] !== undefined);
719
- const extras = [];
720
- for (const key of Object.keys(gigInput)) {
721
- if (standardInputs.has(key))
722
- continue; // a declared key is read, never undeclared
723
- const collidesWith = declaredPresent.find((d) => normalizeKey(d) === normalizeKey(key));
724
- if (collidesWith !== undefined) {
725
- throw new RuntimeError(`dispatch payload key "${key}" is not declared by standard "${standard.slug}", but normalizes to declared gig input "${collidesWith}", which is ALSO present — one of the two spellings is being dropped and the caller cannot see which. Gig input keys are the hyphenated type slug, so rename "${key}" to "${collidesWith}" or drop it.`);
726
- }
727
- extras.push(key);
751
+ // contract-post-time-gig-input-v1 (O2) the partition and its refusal message now live in the
752
+ // shared `partitionGigInputKeys` / `unknownGigInputMessage` builders, which the hosted dispatch
753
+ // door (src/server.ts) also calls, so the two doors cannot drift into two vocabularies. The
754
+ // behaviour here is unchanged: a near miss throws the same RuntimeError, the extras emit the same
755
+ // event. `isPresent` is `gigInput[d] !== undefined`, exactly the collision predicate as before.
756
+ const part = partitionGigInputKeys([...Object.keys(gigInput)], [...standardInputs], (d) => gigInput[d] !== undefined);
757
+ if (part.nearMiss !== undefined) {
758
+ throw new RuntimeError(unknownGigInputMessage(part.nearMiss.key, part.nearMiss.declaredKey, standard.slug));
728
759
  }
729
760
  // The `undeclared_gig_input` variant is intentionally NOT in the GigProgressEvent union: adding it
730
761
  // there would force a matching case in every exhaustive switch over the union (gig_tracker.ts),
731
762
  // which this change's grant (src/runtime.ts, src/cli.ts) may not touch. It is emitted through a
732
763
  // widening cast — exactly the shape the laws read via `evType`/`keysOf` — so a sink that recognises
733
764
  // it sees `{ type, standard, keys }` and one that does not simply no-ops on an unknown `type`.
734
- if (extras.length > 0) {
735
- const ev = { type: "undeclared_gig_input", standard: standard.slug, keys: extras.sort() };
765
+ if (part.extras.length > 0) {
766
+ const ev = { type: "undeclared_gig_input", standard: standard.slug, keys: part.extras };
736
767
  emit(ev);
737
768
  }
738
769
  }