@eir-labs/coltrane 0.10.0 → 0.12.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/agents/bandleader.json +54 -0
- package/agents/bill.json +4 -2
- package/agents/change-verifier.json +2 -1
- package/agents/code-implementer.json +7 -4
- package/agents/john.json +5 -3
- package/agents/lineage-scout-external.json +19 -6
- package/agents/lineage-scribe.json +20 -9
- package/agents/lineage-weaver.json +26 -11
- package/agents/miles.json +2 -1
- package/agents/players/bandleader.md +70 -0
- package/agents/pr-publisher.json +4 -2
- package/agents/red-spec-drafter.json +12 -6
- package/agents/room-prober.json +29 -0
- package/agents/source-walker.json +1 -1
- package/charts/room-probe-chart-v1.json +14 -0
- package/charts/worker-contract-docker-v2.json +135 -0
- package/charts/worker-contract-v3.json +206 -0
- package/dist/src/boundary_check.d.ts +18 -0
- package/dist/src/boundary_check.js +70 -0
- package/dist/src/boundary_check.js.map +1 -0
- package/dist/src/boundary_scan.d.ts +62 -0
- package/dist/src/boundary_scan.js +93 -0
- package/dist/src/boundary_scan.js.map +1 -0
- package/dist/src/chart.js +34 -1
- package/dist/src/chart.js.map +1 -1
- package/dist/src/claude_invoker.d.ts +2 -13
- package/dist/src/claude_invoker.js +242 -18
- package/dist/src/claude_invoker.js.map +1 -1
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/cli.js +115 -27
- package/dist/src/cli.js.map +1 -1
- package/dist/src/drain_preflight.d.ts +33 -0
- package/dist/src/drain_preflight.js +97 -0
- package/dist/src/drain_preflight.js.map +1 -0
- package/dist/src/genome_schema.d.ts +390 -9
- package/dist/src/genome_schema.js +163 -8
- package/dist/src/genome_schema.js.map +1 -1
- package/dist/src/genome_store.js +9 -0
- package/dist/src/genome_store.js.map +1 -1
- package/dist/src/genome_writer.d.ts +1 -1
- package/dist/src/genome_writer.js +10 -2
- package/dist/src/genome_writer.js.map +1 -1
- package/dist/src/gig_conformance.d.ts +66 -0
- package/dist/src/gig_conformance.js +153 -0
- package/dist/src/gig_conformance.js.map +1 -0
- package/dist/src/gig_tracker.js +8 -0
- package/dist/src/gig_tracker.js.map +1 -1
- package/dist/src/grounding.d.ts +44 -0
- package/dist/src/grounding.js +127 -0
- package/dist/src/grounding.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/institution_loader.d.ts +29 -5
- package/dist/src/institution_loader.js +67 -6
- package/dist/src/institution_loader.js.map +1 -1
- package/dist/src/lineage_adoption.d.ts +82 -0
- package/dist/src/lineage_adoption.js +82 -0
- package/dist/src/lineage_adoption.js.map +1 -0
- package/dist/src/lineage_persist.d.ts +34 -0
- package/dist/src/lineage_persist.js +60 -0
- package/dist/src/lineage_persist.js.map +1 -0
- package/dist/src/loader.d.ts +13 -0
- package/dist/src/loader.js +43 -2
- package/dist/src/loader.js.map +1 -1
- package/dist/src/local_queue.d.ts +105 -0
- package/dist/src/local_queue.js +380 -0
- package/dist/src/local_queue.js.map +1 -0
- package/dist/src/mcp.js +37 -4
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/org_hire.d.ts +23 -0
- package/dist/src/org_hire.js +42 -0
- package/dist/src/org_hire.js.map +1 -0
- package/dist/src/outputs.d.ts +17 -0
- package/dist/src/outputs.js +86 -1
- package/dist/src/outputs.js.map +1 -1
- package/dist/src/player_to_claude_code.js +26 -2
- package/dist/src/player_to_claude_code.js.map +1 -1
- package/dist/src/registry.d.ts +3 -1
- package/dist/src/registry.js +43 -3
- package/dist/src/registry.js.map +1 -1
- package/dist/src/repo_index.d.ts +58 -0
- package/dist/src/repo_index.js +232 -0
- package/dist/src/repo_index.js.map +1 -0
- package/dist/src/residency.d.ts +149 -0
- package/dist/src/residency.js +283 -0
- package/dist/src/residency.js.map +1 -0
- package/dist/src/reuse.d.ts +44 -4
- package/dist/src/reuse.js +0 -0
- package/dist/src/reuse.js.map +1 -1
- package/dist/src/runtime.d.ts +82 -0
- package/dist/src/runtime.js +254 -25
- package/dist/src/runtime.js.map +1 -1
- package/dist/src/server.d.ts +37 -0
- package/dist/src/server.js +422 -11
- package/dist/src/server.js.map +1 -1
- package/dist/src/server_relay.d.ts +40 -2
- package/dist/src/server_relay.js +186 -19
- package/dist/src/server_relay.js.map +1 -1
- package/dist/src/tool_providers.d.ts +27 -0
- package/dist/src/tool_providers.js +48 -0
- package/dist/src/tool_providers.js.map +1 -1
- package/dist/src/venue_credential.d.ts +41 -0
- package/dist/src/venue_credential.js +57 -0
- package/dist/src/venue_credential.js.map +1 -0
- package/dist/src/venue_realize.d.ts +23 -0
- package/dist/src/venue_realize.js +43 -3
- package/dist/src/venue_realize.js.map +1 -1
- package/dist/src/venue_realizer.d.ts +224 -0
- package/dist/src/venue_realizer.js +889 -0
- package/dist/src/venue_realizer.js.map +1 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/worker.d.ts +57 -0
- package/dist/src/worker.js +155 -24
- package/dist/src/worker.js.map +1 -1
- package/dist/src/worker_env.d.ts +79 -0
- package/dist/src/worker_env.js +322 -0
- package/dist/src/worker_env.js.map +1 -0
- package/dist/src/workspace.d.ts +12 -1
- package/dist/src/workspace.js +10 -3
- package/dist/src/workspace.js.map +1 -1
- package/domain_types/change-context.json +59 -13
- package/domain_types/lineage-adoption-target.json +22 -0
- package/domain_types/lineage-map.json +7 -2
- package/domain_types/lineage-record.json +55 -5
- package/domain_types/prior-art-hit.json +16 -1
- package/domain_types/red-spec.json +5 -3
- package/domain_types/woodshed-record.json +149 -0
- package/evals/gist-present.json +7 -0
- package/institutions/coltrane.json +178 -6
- package/package.json +6 -3
- package/skills/non-vacuity-probe/fixtures/fixture-001.json +17 -0
- package/skills/non-vacuity-probe/meta.json +12 -0
- package/skills/non-vacuity-probe/skill.md +27 -0
- package/skills/non-vacuity-probe/skill.mjs +81 -0
- package/standards/lineage-adopt-v0.json +37 -0
- package/standards/room-probe-v1.json +28 -0
- package/standards/software-change-pr-v1.json +15 -15
- package/standards/software-change-red-first-v0.json +183 -0
- package/standards/spec-review-and-sequence-v0.json +112 -0
- package/standards/studio-session-v0.json +101 -0
- package/tours/coltrane.json +72 -0
- package/venues/engine-room-v1.json +32 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** Which host a value addresses — or "none" when it names no host at all. */
|
|
2
|
+
export type EnvHost = "service" | "store" | "none";
|
|
3
|
+
/** What kind of thing it is. A url is the only role that MUST name a host. */
|
|
4
|
+
export type EnvRole = "url" | "credential" | "identity" | "tuning";
|
|
5
|
+
/** When a worker must have it. "venue"/"player" are the two credential modes (Gap 4). */
|
|
6
|
+
export type EnvRequired = "always" | "venue" | "player" | "conditional" | "never";
|
|
7
|
+
/**
|
|
8
|
+
* The answer to "which credential mode is this worker in", carrying what the answer needs so a call
|
|
9
|
+
* site consumes it instead of re-reading the environment and re-deciding (Gap 4). `why` is the
|
|
10
|
+
* refusal text, single-sourced: the CLI prints exactly this string.
|
|
11
|
+
*/
|
|
12
|
+
export type WorkerCredentialMode = {
|
|
13
|
+
mode: "venue";
|
|
14
|
+
drainKey: string;
|
|
15
|
+
instance: string;
|
|
16
|
+
} | {
|
|
17
|
+
mode: "player";
|
|
18
|
+
agentToken: string;
|
|
19
|
+
} | {
|
|
20
|
+
mode: "none";
|
|
21
|
+
why: string;
|
|
22
|
+
};
|
|
23
|
+
export interface WorkerEnvVar {
|
|
24
|
+
name: string;
|
|
25
|
+
host: EnvHost;
|
|
26
|
+
role: EnvRole;
|
|
27
|
+
required: EnvRequired;
|
|
28
|
+
/** one sentence: what it means and, for a url, WHICH host it names. */
|
|
29
|
+
meaning: string;
|
|
30
|
+
/** names tolerated for compatibility and normalized onto `name`. */
|
|
31
|
+
legacy_names?: readonly string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* THE ENUMERATED TABLE. Every environment variable the worker path reads appears here exactly once,
|
|
35
|
+
* as a `name` or as one entry's `legacy_names`. Exactly one always-required url names each host
|
|
36
|
+
* (store, service); no name is listed twice; no legacy alias is also someone's canonical name.
|
|
37
|
+
*/
|
|
38
|
+
export declare const WORKER_ENV_CONTRACT: readonly WorkerEnvVar[];
|
|
39
|
+
/**
|
|
40
|
+
* Normalize a worker environment onto its canonical shape — it NORMALIZES, it never appends.
|
|
41
|
+
*
|
|
42
|
+
* * strips a legacy `/rest/v1` path suffix from the service url rather than building on top of it;
|
|
43
|
+
* * maps the legacy name (`COLTRANE_DRAIN_URL`) onto the canonical `COLTRANE_SERVICE_URL`;
|
|
44
|
+
* * treats the hosting provider's app name (`FLY_APP_NAME`) as a legacy alias of `COLTRANE_INSTANCE`;
|
|
45
|
+
* * is IDEMPOTENT — applying it to its own output changes nothing.
|
|
46
|
+
*
|
|
47
|
+
* The legacy keys are dropped from the output: a normalized environment carries only canonical
|
|
48
|
+
* names, which is what makes re-application a no-op.
|
|
49
|
+
*/
|
|
50
|
+
export declare function normalizeWorkerEnv(env: Record<string, string | undefined>): Record<string, string>;
|
|
51
|
+
/**
|
|
52
|
+
* Which credential mode a worker is in — the SINGLE derivation of it (Gap 4). Both the CLI door and
|
|
53
|
+
* the claim path ask this one function instead of each recomputing `drainKey && instance`; the
|
|
54
|
+
* answer carries the fields the answer needs, so no call site re-reads the environment to fill them
|
|
55
|
+
* in, and its refusal (`why`) is the refusal the CLI prints. It is the only place that decides.
|
|
56
|
+
*
|
|
57
|
+
* Reads the RAW environment for the same reason `assertWorkerEnv` does: the instance may arrive
|
|
58
|
+
* under the legacy `FLY_APP_NAME` alias, and normalizing first would drop that alias, so a
|
|
59
|
+
* venue-key-without-instance could no longer be told apart from a properly named venue.
|
|
60
|
+
*
|
|
61
|
+
* Precedence, and the reasons:
|
|
62
|
+
* * A drain key present makes this a venue box. With an instance it is venue mode; WITHOUT one it
|
|
63
|
+
* REFUSES — even when a player token is sitting right there. A half-configured venue that quietly
|
|
64
|
+
* ran as a player would claim a different set of gigs under a different identity, and the operator
|
|
65
|
+
* would see a queue that merely looked empty. Venue therefore wins over player, and its own
|
|
66
|
+
* misconfiguration is a refusal, not a downgrade.
|
|
67
|
+
* * A player token alone is player mode.
|
|
68
|
+
* * Neither credential is a refusal that names BOTH doors, because either one would work.
|
|
69
|
+
*/
|
|
70
|
+
export declare function workerCredentialMode(env: Record<string, string | undefined>): WorkerCredentialMode;
|
|
71
|
+
/**
|
|
72
|
+
* Refuse a misconfigured worker at STARTUP, naming the offending variable in the error — never
|
|
73
|
+
* silently picking a winner, and never learning it from a status code at the first write.
|
|
74
|
+
*
|
|
75
|
+
* Reads the RAW environment. The legacy-alias contradiction check in particular must NOT normalize
|
|
76
|
+
* first: normalizing collapses `COLTRANE_DRAIN_URL` onto `COLTRANE_SERVICE_URL`, leaving nothing to
|
|
77
|
+
* contradict — so the check would pass on exactly the environment it exists to refuse.
|
|
78
|
+
*/
|
|
79
|
+
export declare function assertWorkerEnv(env: Record<string, string | undefined>): void;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// The worker environment contract, written down in ONE place — the fix for Gap 3 of
|
|
2
|
+
// SPEC-worker-contract.md.
|
|
3
|
+
//
|
|
4
|
+
// ONE VARIABLE, THREE READERS, TWO MEANINGS. `COLTRANE_DRAIN_URL` was read by callers that did not
|
|
5
|
+
// agree on what host it named — two treated it as the database's PostgREST base, one as the
|
|
6
|
+
// Coltrane service origin. Pointed at the database, rows wrote and the artifact 401'd forever;
|
|
7
|
+
// repointed at the service, provisioning broke against a 307. Every fix moved the failure because
|
|
8
|
+
// the variable had never named one thing.
|
|
9
|
+
//
|
|
10
|
+
// This module pins the general form of the fix rather than that instance of it:
|
|
11
|
+
// * one variable names one host; two hosts are two variables (`WORKER_ENV_CONTRACT`);
|
|
12
|
+
// * `COLTRANE_SERVICE_URL` is canonical and `COLTRANE_DRAIN_URL` survives only as a normalized
|
|
13
|
+
// legacy alias — a role name is not a host name, which is how one variable came to hold both;
|
|
14
|
+
// * a legacy shape NORMALIZES, never appends (`normalizeWorkerEnv`) — appending is what produced
|
|
15
|
+
// `/rest/v1/rest/v1`;
|
|
16
|
+
// * a misconfigured worker refuses at STARTUP in its own voice (`assertWorkerEnv`), rather than
|
|
17
|
+
// learning it is pointed at the wrong host from a status code at its first write.
|
|
18
|
+
//
|
|
19
|
+
// The contract enumerates every variable the worker path reads. `tests/spec_worker_environment.test.ts`
|
|
20
|
+
// scans the real source of the WORKER_PATH files and fails if any `process.env["…"]` read is absent
|
|
21
|
+
// from this table — so the table is a declaration the code is held to, not a comment. This file
|
|
22
|
+
// therefore reads NO environment itself; its three functions take the environment as an argument.
|
|
23
|
+
/**
|
|
24
|
+
* THE ENUMERATED TABLE. Every environment variable the worker path reads appears here exactly once,
|
|
25
|
+
* as a `name` or as one entry's `legacy_names`. Exactly one always-required url names each host
|
|
26
|
+
* (store, service); no name is listed twice; no legacy alias is also someone's canonical name.
|
|
27
|
+
*/
|
|
28
|
+
export const WORKER_ENV_CONTRACT = [
|
|
29
|
+
{
|
|
30
|
+
name: "COLTRANE_STORE_URL",
|
|
31
|
+
host: "store",
|
|
32
|
+
role: "url",
|
|
33
|
+
required: "always",
|
|
34
|
+
meaning: "The PostgREST base URL of the store — the database host that persists gigs, outputs and ledger rows and that the claim path reads directly.",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "COLTRANE_STORE_ANON",
|
|
38
|
+
host: "none",
|
|
39
|
+
role: "credential",
|
|
40
|
+
required: "always",
|
|
41
|
+
meaning: "The store's public anon API key, presented to the store on the claim path as its `apikey`; it is not a write credential.",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "COLTRANE_SERVICE_URL",
|
|
45
|
+
host: "service",
|
|
46
|
+
role: "url",
|
|
47
|
+
required: "always",
|
|
48
|
+
meaning: "The origin of the Coltrane service that brokers drain writes and boot-time provisioning — names the service host, and never the managed database.",
|
|
49
|
+
legacy_names: ["COLTRANE_DRAIN_URL"],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "COLTRANE_DRAIN_KEY",
|
|
53
|
+
host: "none",
|
|
54
|
+
role: "credential",
|
|
55
|
+
required: "venue",
|
|
56
|
+
meaning: "The venue's org-scoped `cdk_` drain credential authorizing output writes through the service on behalf of the whole instance.",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "COLTRANE_AGENT_TOKEN",
|
|
60
|
+
host: "none",
|
|
61
|
+
role: "credential",
|
|
62
|
+
required: "player",
|
|
63
|
+
meaning: "A single agent's own `ctk_` bearer token, identifying the player to the store in player mode instead of a shared venue key.",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "COLTRANE_INSTANCE",
|
|
67
|
+
host: "none",
|
|
68
|
+
role: "identity",
|
|
69
|
+
required: "conditional",
|
|
70
|
+
meaning: "The name this worker box answers to, stamped on every drain write so the store can gate the write against a live lease; absent for an unleased local run.",
|
|
71
|
+
legacy_names: ["FLY_APP_NAME"],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "COLTRANE_DRAIN_PG",
|
|
75
|
+
host: "none",
|
|
76
|
+
role: "credential",
|
|
77
|
+
required: "never",
|
|
78
|
+
meaning: "Legacy direct-Postgres connection string for the drain — a fallback sink reached only when no service drain key is configured.",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "COLTRANE_DRAIN_BUCKET",
|
|
82
|
+
host: "none",
|
|
83
|
+
role: "tuning",
|
|
84
|
+
required: "never",
|
|
85
|
+
meaning: "Name of the storage bucket that drain artifacts are written into; defaults to `coltrane-artifacts` when unset.",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "COLTRANE_DRAIN_OPENING",
|
|
89
|
+
host: "none",
|
|
90
|
+
role: "tuning",
|
|
91
|
+
required: "never",
|
|
92
|
+
meaning: "Milliseconds the drain waits for a gig's opening header before proceeding; tunes drain startup latency.",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "COLTRANE_MIRROR_DIR",
|
|
96
|
+
host: "none",
|
|
97
|
+
role: "tuning",
|
|
98
|
+
required: "never",
|
|
99
|
+
meaning: "Local directory the output mirror writes a copy of every sealed artifact into for offline inspection.",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "COLTRANE_GIT_CREDENTIALS_URL",
|
|
103
|
+
host: "none",
|
|
104
|
+
role: "tuning",
|
|
105
|
+
required: "never",
|
|
106
|
+
meaning: "Endpoint the worker asks for a short-lived git credential when cloning a lease's repository; unset outside a leased drain.",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "COLTRANE_MODEL",
|
|
110
|
+
host: "none",
|
|
111
|
+
role: "tuning",
|
|
112
|
+
required: "never",
|
|
113
|
+
meaning: "Overrides the model version a chair invokes and is recorded on outputs as the model that produced them.",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "COLTRANE_CHAIR_TIMEOUT_MS",
|
|
117
|
+
host: "none",
|
|
118
|
+
role: "tuning",
|
|
119
|
+
required: "never",
|
|
120
|
+
meaning: "Per-chair wall-clock timeout in milliseconds before a running chair invocation is abandoned.",
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "COLTRANE_GIG_TIMEOUT_MS",
|
|
124
|
+
host: "none",
|
|
125
|
+
role: "tuning",
|
|
126
|
+
required: "never",
|
|
127
|
+
meaning: "Overall wall-clock timeout in milliseconds for a single gig before the worker abandons it.",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: "COLTRANE_WORKER_CHECKPOINTS",
|
|
131
|
+
host: "none",
|
|
132
|
+
role: "tuning",
|
|
133
|
+
required: "never",
|
|
134
|
+
meaning: "Overrides the worker's checkpoint cadence, controlling how often in-progress run state is persisted to disk.",
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "COLTRANE_WORKER_STATE_TTL_DAYS",
|
|
138
|
+
host: "none",
|
|
139
|
+
role: "tuning",
|
|
140
|
+
required: "never",
|
|
141
|
+
meaning: "Days a worker retains persisted run state before it is considered stale and eligible for pruning.",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: "COLTRANE_TOOL_PROVIDERS",
|
|
145
|
+
host: "none",
|
|
146
|
+
role: "tuning",
|
|
147
|
+
required: "never",
|
|
148
|
+
meaning: "Comma-separated list of tool providers the worker is permitted to load, narrowing the tool surface a chair may reach.",
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
/** The canonical service-url entry — the one host the legacy `COLTRANE_DRAIN_URL` normalizes onto. */
|
|
152
|
+
const SERVICE_URL = "COLTRANE_SERVICE_URL";
|
|
153
|
+
/** The canonical store-url entry — the database host, which must never be the same as the service. */
|
|
154
|
+
const STORE_URL = "COLTRANE_STORE_URL";
|
|
155
|
+
/** The legacy role-name that once held both meanings; now a normalized alias of the service url. */
|
|
156
|
+
const DRAIN_URL = "COLTRANE_DRAIN_URL";
|
|
157
|
+
/** The managed database's host shape. A service url naming this is the defect in its purest form. */
|
|
158
|
+
const MANAGED_DB_HOST = /(^|\.)supabase\.(co|in|net)$/i;
|
|
159
|
+
/** Parseable as an http(s) URL — the shape a `role: "url"` variable must have. */
|
|
160
|
+
function isHttpUrl(value) {
|
|
161
|
+
try {
|
|
162
|
+
const u = new URL(value);
|
|
163
|
+
return u.protocol === "http:" || u.protocol === "https:";
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/** The host a url addresses, or "" when it does not parse — for comparing two urls' hosts. */
|
|
170
|
+
function urlHost(value) {
|
|
171
|
+
try {
|
|
172
|
+
return new URL(value).host.toLowerCase();
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return "";
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Strip the legacy `/rest/v1` suffix an origin may carry from when it named a database. Mirrors
|
|
180
|
+
* `src/output_mirror.ts:317-320`: build from the ORIGIN, so a suffix that survives a redeploy can
|
|
181
|
+
* never be appended-to and produce `/rest/v1/rest/v1`.
|
|
182
|
+
*/
|
|
183
|
+
function serviceOrigin(value) {
|
|
184
|
+
return value.replace(/\/+$/, "").replace(/\/rest\/v1$/, "");
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Normalize a worker environment onto its canonical shape — it NORMALIZES, it never appends.
|
|
188
|
+
*
|
|
189
|
+
* * strips a legacy `/rest/v1` path suffix from the service url rather than building on top of it;
|
|
190
|
+
* * maps the legacy name (`COLTRANE_DRAIN_URL`) onto the canonical `COLTRANE_SERVICE_URL`;
|
|
191
|
+
* * treats the hosting provider's app name (`FLY_APP_NAME`) as a legacy alias of `COLTRANE_INSTANCE`;
|
|
192
|
+
* * is IDEMPOTENT — applying it to its own output changes nothing.
|
|
193
|
+
*
|
|
194
|
+
* The legacy keys are dropped from the output: a normalized environment carries only canonical
|
|
195
|
+
* names, which is what makes re-application a no-op.
|
|
196
|
+
*/
|
|
197
|
+
export function normalizeWorkerEnv(env) {
|
|
198
|
+
const out = {};
|
|
199
|
+
for (const [k, v] of Object.entries(env)) {
|
|
200
|
+
if (v !== undefined)
|
|
201
|
+
out[k] = v;
|
|
202
|
+
}
|
|
203
|
+
// A legacy name fills the canonical one only when the canonical is not already set, then is
|
|
204
|
+
// dropped — mapping, not appending.
|
|
205
|
+
const legacyService = out[DRAIN_URL];
|
|
206
|
+
if (legacyService !== undefined && out[SERVICE_URL] === undefined) {
|
|
207
|
+
out[SERVICE_URL] = legacyService;
|
|
208
|
+
}
|
|
209
|
+
delete out[DRAIN_URL];
|
|
210
|
+
const legacyInstance = out["FLY_APP_NAME"];
|
|
211
|
+
if (legacyInstance !== undefined && out["COLTRANE_INSTANCE"] === undefined) {
|
|
212
|
+
out["COLTRANE_INSTANCE"] = legacyInstance;
|
|
213
|
+
}
|
|
214
|
+
delete out["FLY_APP_NAME"];
|
|
215
|
+
const service = out[SERVICE_URL];
|
|
216
|
+
if (service !== undefined) {
|
|
217
|
+
out[SERVICE_URL] = serviceOrigin(service);
|
|
218
|
+
}
|
|
219
|
+
return out;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Which credential mode a worker is in — the SINGLE derivation of it (Gap 4). Both the CLI door and
|
|
223
|
+
* the claim path ask this one function instead of each recomputing `drainKey && instance`; the
|
|
224
|
+
* answer carries the fields the answer needs, so no call site re-reads the environment to fill them
|
|
225
|
+
* in, and its refusal (`why`) is the refusal the CLI prints. It is the only place that decides.
|
|
226
|
+
*
|
|
227
|
+
* Reads the RAW environment for the same reason `assertWorkerEnv` does: the instance may arrive
|
|
228
|
+
* under the legacy `FLY_APP_NAME` alias, and normalizing first would drop that alias, so a
|
|
229
|
+
* venue-key-without-instance could no longer be told apart from a properly named venue.
|
|
230
|
+
*
|
|
231
|
+
* Precedence, and the reasons:
|
|
232
|
+
* * A drain key present makes this a venue box. With an instance it is venue mode; WITHOUT one it
|
|
233
|
+
* REFUSES — even when a player token is sitting right there. A half-configured venue that quietly
|
|
234
|
+
* ran as a player would claim a different set of gigs under a different identity, and the operator
|
|
235
|
+
* would see a queue that merely looked empty. Venue therefore wins over player, and its own
|
|
236
|
+
* misconfiguration is a refusal, not a downgrade.
|
|
237
|
+
* * A player token alone is player mode.
|
|
238
|
+
* * Neither credential is a refusal that names BOTH doors, because either one would work.
|
|
239
|
+
*/
|
|
240
|
+
export function workerCredentialMode(env) {
|
|
241
|
+
const drainKey = env["COLTRANE_DRAIN_KEY"];
|
|
242
|
+
const agentToken = env["COLTRANE_AGENT_TOKEN"];
|
|
243
|
+
const instance = env["COLTRANE_INSTANCE"] ?? env["FLY_APP_NAME"];
|
|
244
|
+
if (drainKey) {
|
|
245
|
+
if (instance)
|
|
246
|
+
return { mode: "venue", drainKey, instance };
|
|
247
|
+
return {
|
|
248
|
+
mode: "none",
|
|
249
|
+
why: "COLTRANE_DRAIN_KEY is set but no instance is named — the key is bound to one venue and the " +
|
|
250
|
+
"store cannot tell which. Set COLTRANE_INSTANCE (or FLY_APP_NAME) so the drain key can be presented.",
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
if (agentToken)
|
|
254
|
+
return { mode: "player", agentToken };
|
|
255
|
+
return {
|
|
256
|
+
mode: "none",
|
|
257
|
+
why: "work needs a credential: EITHER a venue drain key (COLTRANE_DRAIN_KEY with COLTRANE_INSTANCE " +
|
|
258
|
+
"or FLY_APP_NAME) OR a player token (COLTRANE_AGENT_TOKEN). A drain should hold the venue " +
|
|
259
|
+
"credential: it claims any gig dispatched to its org and runs each as that gig's own acting_for.",
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Refuse a misconfigured worker at STARTUP, naming the offending variable in the error — never
|
|
264
|
+
* silently picking a winner, and never learning it from a status code at the first write.
|
|
265
|
+
*
|
|
266
|
+
* Reads the RAW environment. The legacy-alias contradiction check in particular must NOT normalize
|
|
267
|
+
* first: normalizing collapses `COLTRANE_DRAIN_URL` onto `COLTRANE_SERVICE_URL`, leaving nothing to
|
|
268
|
+
* contradict — so the check would pass on exactly the environment it exists to refuse.
|
|
269
|
+
*/
|
|
270
|
+
export function assertWorkerEnv(env) {
|
|
271
|
+
// (a) Every always-required variable must be present. A legacy alias satisfies its canonical.
|
|
272
|
+
for (const v of WORKER_ENV_CONTRACT) {
|
|
273
|
+
if (v.required !== "always")
|
|
274
|
+
continue;
|
|
275
|
+
const present = env[v.name] ?? (v.legacy_names ?? []).map((n) => env[n]).find((x) => x != null && x !== "");
|
|
276
|
+
if (present == null || present === "") {
|
|
277
|
+
throw new Error(`${v.name} is required but absent — ${v.meaning}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// (b) Every url-role variable that is present must actually be a url. Checked before any host
|
|
281
|
+
// comparison so the parsing below is safe.
|
|
282
|
+
for (const v of WORKER_ENV_CONTRACT) {
|
|
283
|
+
if (v.role !== "url")
|
|
284
|
+
continue;
|
|
285
|
+
const value = env[v.name] ?? (v.legacy_names ?? []).map((n) => env[n]).find((x) => x != null);
|
|
286
|
+
if (value != null && value !== "" && !isHttpUrl(value)) {
|
|
287
|
+
throw new Error(`${v.name} is a url but does not parse as one: ${value}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const serviceRaw = env[SERVICE_URL] ?? env[DRAIN_URL];
|
|
291
|
+
const storeRaw = env[STORE_URL];
|
|
292
|
+
// (c) The service url must not name the managed database — checked BEFORE the first request, the
|
|
293
|
+
// diagnostic moved from output_mirror.ts to startup where it belongs.
|
|
294
|
+
if (serviceRaw != null && serviceRaw !== "" && MANAGED_DB_HOST.test(urlHost(serviceRaw))) {
|
|
295
|
+
throw new Error(`${SERVICE_URL} names the managed database (${serviceRaw}). It must name the Coltrane service, ` +
|
|
296
|
+
"which brokers both halves of a write; a drain key is not a project credential and Storage will refuse it.");
|
|
297
|
+
}
|
|
298
|
+
// (d) The store and the service must not name the same host — the general form of "pointed at the
|
|
299
|
+
// database", detectable without knowing which of the two is wrong.
|
|
300
|
+
if (serviceRaw != null &&
|
|
301
|
+
serviceRaw !== "" &&
|
|
302
|
+
storeRaw != null &&
|
|
303
|
+
storeRaw !== "" &&
|
|
304
|
+
urlHost(serviceRaw) !== "" &&
|
|
305
|
+
urlHost(serviceRaw) === urlHost(storeRaw)) {
|
|
306
|
+
throw new Error(`${STORE_URL} and ${SERVICE_URL} name the same host (${urlHost(serviceRaw)}) — a store and a ` +
|
|
307
|
+
"service are two hosts, and one url pointed at both is how three readers came to disagree.");
|
|
308
|
+
}
|
|
309
|
+
// (e) A legacy alias that CONTRADICTS the canonical name refuses, naming both — read raw, because
|
|
310
|
+
// normalization would erase the disagreement. Agreement is the ordinary post-redeploy case.
|
|
311
|
+
const drainRaw = env[DRAIN_URL];
|
|
312
|
+
const serviceCanonical = env[SERVICE_URL];
|
|
313
|
+
if (drainRaw != null &&
|
|
314
|
+
drainRaw !== "" &&
|
|
315
|
+
serviceCanonical != null &&
|
|
316
|
+
serviceCanonical !== "" &&
|
|
317
|
+
serviceOrigin(drainRaw) !== serviceOrigin(serviceCanonical)) {
|
|
318
|
+
throw new Error(`${DRAIN_URL} (${drainRaw}) disagrees with ${SERVICE_URL} (${serviceCanonical}). ${DRAIN_URL} is a ` +
|
|
319
|
+
`legacy alias of ${SERVICE_URL}; set one, or make them agree.`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=worker_env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker_env.js","sourceRoot":"","sources":["../../src/worker_env.ts"],"names":[],"mappings":"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"}
|
package/dist/src/workspace.d.ts
CHANGED
|
@@ -69,8 +69,15 @@ export declare function fetchGitCredential(endpoint: string, drainKey: string, i
|
|
|
69
69
|
* The helper is supplied through GIT_CONFIG_* rather than `-c`, because `git clone -c k=v` writes k
|
|
70
70
|
* into the NEW clone's .git/config — see the note at the call site. Scoped to `https://github.com`
|
|
71
71
|
* so a URL naming any other host is never offered the token.
|
|
72
|
+
*
|
|
73
|
+
* `targetDir`, when given, is WHERE the clone lands — a caller-supplied directory instead of this
|
|
74
|
+
* function's own throwaway tmpdir. It is the one addition a venue room needs over the drain: the room
|
|
75
|
+
* clones into `<realizationDir>/workspace` (the seat's cwd, subsumed by the realizer's own teardown)
|
|
76
|
+
* rather than a detached tmpdir. Everything else — the token-never-on-disk GIT_CONFIG_* path, cleanup,
|
|
77
|
+
* revoke — is IDENTICAL, because a room's working tree and the drain's must be the same thing prepared
|
|
78
|
+
* the same way. Omitted (the drain's call) keeps the original mkdtempSync behaviour byte-for-byte.
|
|
72
79
|
*/
|
|
73
|
-
export declare function cloneInto(repoUrl: string, token: string): PreparedWorkspace;
|
|
80
|
+
export declare function cloneInto(repoUrl: string, token: string, targetDir?: string): PreparedWorkspace;
|
|
74
81
|
/**
|
|
75
82
|
* Everything above, for one claimed gig — or null when the claim names no repository.
|
|
76
83
|
*
|
|
@@ -86,4 +93,8 @@ export declare function prepareWorkspace(opts: {
|
|
|
86
93
|
drainKey: string | undefined;
|
|
87
94
|
instance: string | undefined;
|
|
88
95
|
endpoint: string | undefined;
|
|
96
|
+
/** Where the clone lands. Omitted (the drain) → cloneInto's own throwaway tmpdir. Supplied (a venue
|
|
97
|
+
* room) → `<realizationDir>/workspace`, so the seat's cwd is the room's tree and the realizer's
|
|
98
|
+
* existing teardown subsumes the clone. The credential path is unchanged either way. */
|
|
99
|
+
target?: string | undefined;
|
|
89
100
|
}): Promise<PreparedWorkspace | null>;
|
package/dist/src/workspace.js
CHANGED
|
@@ -64,9 +64,16 @@ export async function fetchGitCredential(endpoint, drainKey, instance, gigId) {
|
|
|
64
64
|
* The helper is supplied through GIT_CONFIG_* rather than `-c`, because `git clone -c k=v` writes k
|
|
65
65
|
* into the NEW clone's .git/config — see the note at the call site. Scoped to `https://github.com`
|
|
66
66
|
* so a URL naming any other host is never offered the token.
|
|
67
|
+
*
|
|
68
|
+
* `targetDir`, when given, is WHERE the clone lands — a caller-supplied directory instead of this
|
|
69
|
+
* function's own throwaway tmpdir. It is the one addition a venue room needs over the drain: the room
|
|
70
|
+
* clones into `<realizationDir>/workspace` (the seat's cwd, subsumed by the realizer's own teardown)
|
|
71
|
+
* rather than a detached tmpdir. Everything else — the token-never-on-disk GIT_CONFIG_* path, cleanup,
|
|
72
|
+
* revoke — is IDENTICAL, because a room's working tree and the drain's must be the same thing prepared
|
|
73
|
+
* the same way. Omitted (the drain's call) keeps the original mkdtempSync behaviour byte-for-byte.
|
|
67
74
|
*/
|
|
68
|
-
export function cloneInto(repoUrl, token) {
|
|
69
|
-
const dir = mkdtempSync(join(tmpdir(), "coltrane-gig-"));
|
|
75
|
+
export function cloneInto(repoUrl, token, targetDir) {
|
|
76
|
+
const dir = targetDir ?? mkdtempSync(join(tmpdir(), "coltrane-gig-"));
|
|
70
77
|
const cleanup = () => {
|
|
71
78
|
try {
|
|
72
79
|
rmSync(dir, { recursive: true, force: true });
|
|
@@ -136,6 +143,6 @@ export async function prepareWorkspace(opts) {
|
|
|
136
143
|
`nowhere to obtain a credential scoped to this gig`);
|
|
137
144
|
}
|
|
138
145
|
const cred = await fetchGitCredential(opts.endpoint, opts.drainKey, opts.instance, opts.gigId);
|
|
139
|
-
return cloneInto(opts.repoUrl, cred.token);
|
|
146
|
+
return cloneInto(opts.repoUrl, cred.token, opts.target);
|
|
140
147
|
}
|
|
141
148
|
//# sourceMappingURL=workspace.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAgCjC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,KAAa;IAEb,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;KACvE,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,MAAM,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,GAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAwB,CAAC,KAAK,IAAI,IAAI,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC,CAAC,uBAAuB,CAAC,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,CAAC,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4C,CAAC;IACzE,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC9E,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC5F,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,32 +1,78 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "change-context",
|
|
3
|
-
"version":
|
|
3
|
+
"version": 2,
|
|
4
4
|
"extends": "Interpretation",
|
|
5
5
|
"domain": "software-change",
|
|
6
6
|
"status": "active",
|
|
7
|
-
"description": "The exhaustive read of the material a change lands in, produced before any decision is taken. Records what is present AND what is absent: unknowns is required because an incomplete reading that omits its gaps is indistinguishable from a complete one, and every downstream seat would treat it as complete.",
|
|
8
7
|
"schema": {
|
|
9
8
|
"type": "object",
|
|
10
9
|
"properties": {
|
|
11
|
-
"repository":
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Repository or working-tree the reading covers."
|
|
13
|
+
},
|
|
14
|
+
"boundary": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": {
|
|
17
|
+
"type": "string"
|
|
18
|
+
},
|
|
19
|
+
"description": "The declared extent of the read: paths and artefacts inside it, and those deliberately outside it."
|
|
20
|
+
},
|
|
21
|
+
"entry_points": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"description": "Where control or data enters the region under change."
|
|
27
|
+
},
|
|
28
|
+
"relevant_files": {
|
|
15
29
|
"type": "array",
|
|
16
30
|
"description": "Each file the change plausibly touches, with the reason it is relevant and the locator the reading came from.",
|
|
17
31
|
"items": {
|
|
18
32
|
"type": "object",
|
|
19
33
|
"properties": {
|
|
20
|
-
"path":
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
"path": {
|
|
35
|
+
"type": "string"
|
|
36
|
+
},
|
|
37
|
+
"why": {
|
|
38
|
+
"type": "string"
|
|
39
|
+
},
|
|
40
|
+
"locator": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Tool plus path or query that produced this finding."
|
|
43
|
+
}
|
|
23
44
|
},
|
|
24
|
-
"required": [
|
|
45
|
+
"required": [
|
|
46
|
+
"path",
|
|
47
|
+
"why"
|
|
48
|
+
]
|
|
25
49
|
}
|
|
26
50
|
},
|
|
27
|
-
"existing_tests":
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
"existing_tests": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"items": {
|
|
54
|
+
"type": "string"
|
|
55
|
+
},
|
|
56
|
+
"description": "Checks that already cover the region — the baseline a later verdict is measured against."
|
|
57
|
+
},
|
|
58
|
+
"conventions_observed": {
|
|
59
|
+
"type": "array",
|
|
60
|
+
"items": {
|
|
61
|
+
"type": "string"
|
|
62
|
+
},
|
|
63
|
+
"description": "Prevailing patterns the change is expected to hold to."
|
|
64
|
+
},
|
|
65
|
+
"unknowns": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"items": {
|
|
68
|
+
"type": "string"
|
|
69
|
+
},
|
|
70
|
+
"description": "Questions the material does not answer and paths that could not be reached. Required: the honest bound of the read."
|
|
71
|
+
},
|
|
72
|
+
"index_revision": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"description": "The source revision the MECHANICAL half of this reading was compiled against — the tree state src/repo_index.ts walked. Present when a compiler produced those fields, absent when a human or a model read the code directly. It is what makes the freshness gate possible (#424 I16): a change-context whose index_revision no longer matches the current source describes a tree that has moved, and is refused rather than used. Structure compiled from a stale tree is not merely old, it is WRONG in the specific way that is hardest to notice — the shape is right, the file:line locators are plausible, and every one of them points at the wrong place. OPTIONAL by construction: a change-context may come from any of four interchangeable producers (a reader, the compiler, a prior standard, a human) and only the compiler has a revision to report, so requiring it would make the type unsatisfiable for the three that read code directly — which is the producer-agnosticism I11 pins."
|
|
75
|
+
}
|
|
30
76
|
}
|
|
31
77
|
},
|
|
32
78
|
"required_fields": [
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "lineage-adoption-target",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"extends": "Signal",
|
|
5
|
+
"domain": "lineage",
|
|
6
|
+
"status": "active",
|
|
7
|
+
"description": "WHICH INSTITUTION an approved lineage-record grounds. Both lineage-record and lineage-verdict promise an attachment neither carries: the record says that on approval it 'becomes first-class lineage attached to an institution, inherited by every agent seated there', and the verdict says a passing verdict 'promotes the record to first-class institutional lineage' — yet neither holds an institution_slug, so a sealed adoption named no target and the caller had to know it out of band. The attachment is not a property of the LINEAGE: the same record can ground two institutions and nothing about its ancestry changes when it does. It is not a property of the APPROVAL either: the approver judges whether the evidence is sound, which is a question about grounding rather than about attachment. It is a property of the ADOPTION ACT. One record, approved once, may be adopted into two institutions by two separate acts, each with its own approver and its own seal. Carrying it here rather than on either sealed type also means no shared type changes shape, and lineage-adopt-v0's chair is already an ENTRY chair, so the target arrives the same way the record does — in the dispatch payload.",
|
|
8
|
+
"schema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"institution_slug": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "The institution this adoption grounds. Must resolve against the loaded genome; an unresolved slug is a dead name and fails closed rather than adopting into nothing."
|
|
14
|
+
},
|
|
15
|
+
"note": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Optional. Why THIS institution, when a record could ground more than one. Recorded beside the act rather than inferred from it later."
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"required_fields": ["source", "institution_slug"]
|
|
22
|
+
}
|
|
@@ -21,9 +21,14 @@
|
|
|
21
21
|
"enum": ["descends-from", "aligns-with", "diverges-from", "supersedes", "informed-by"]
|
|
22
22
|
},
|
|
23
23
|
"grounding_internal": { "type": "string" },
|
|
24
|
-
"grounding_external": { "type": "string" }
|
|
24
|
+
"grounding_external": { "type": "string" },
|
|
25
|
+
"strength": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"enum": ["dereferenceable-both-sides", "structural-correspondence", "conceptual-analogy"],
|
|
28
|
+
"$comment": "The weaver DRAWS the grounding strength; the scribe carries it through unchanged into the lineage-record. Ordinal, closed vocabulary — see domain_types/lineage-record.json for the orthogonality note against CitationSchema.evidence_grade (src/genome_schema.ts:293-309)."
|
|
29
|
+
}
|
|
25
30
|
},
|
|
26
|
-
"required": ["internal_ref", "external_ref", "relation", "grounding_internal", "grounding_external"]
|
|
31
|
+
"required": ["internal_ref", "external_ref", "relation", "grounding_internal", "grounding_external", "strength"]
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
}
|