@pome-sh/cli 0.26.8 → 0.26.10
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/build-info.json +3 -3
- package/dist/{checks-UOJUUVZB.js → checks-3LVRPHOK.js} +4 -4
- package/dist/{chunk-IDNSKKEC.js → chunk-2ZGVDTJC.js} +1 -1
- package/dist/{chunk-OFA4E6RJ.js → chunk-6IVXTU67.js} +4 -4
- package/dist/{chunk-JUESW6G4.js → chunk-6KJC4BTO.js} +5 -5
- package/dist/{chunk-7WPD3DTO.js → chunk-ANKO3RCB.js} +7 -7
- package/dist/{chunk-KSX2PAEI.js → chunk-BZO3YCJS.js} +27 -27
- package/dist/{chunk-WEKJIGUD.js → chunk-CFXEETE3.js} +4 -4
- package/dist/{chunk-U6MQ5KBT.js → chunk-CXGMLUZ4.js} +1 -1
- package/dist/{chunk-CKN743FJ.js → chunk-EIUCTFQV.js} +11 -11
- package/dist/{chunk-NUXVJ4E6.js → chunk-FQGR7KDT.js} +4 -4
- package/dist/{chunk-2Q3P45LK.js → chunk-IZFM7W2V.js} +1 -1
- package/dist/{chunk-5EE7YWA3.js → chunk-KIXYRPVY.js} +2 -2
- package/dist/{chunk-B22TYIEM.js → chunk-QXQAVKTE.js} +6 -6
- package/dist/{runDemo-MZPIXV6R.js → runDemo-XO5R5QTM.js} +8 -8
- package/dist/{runTrialGroup-INW4QLSL.js → runTrialGroup-CLJJOO4J.js} +11 -11
- package/dist/{server-TPAFPKLC.js → server-TK5YBK6E.js} +2 -2
- package/dist/src/cli/main.js +33 -33
- package/dist/{src-AAF7TZMO.js → src-FXRQSKBK.js} +31 -32
- package/dist/{src-2M54EY2P.js → src-GWA7QVQS.js} +9 -9
- package/dist/{src-UEO2KIBJ.js → src-JJNS46T6.js} +55 -55
- package/dist/{src-4E5WAGNJ.js → src-L6F5YXSP.js} +14 -14
- package/dist/{src-Q4MBHYC5.js → src-Q4JNJE5S.js} +14 -14
- package/dist/twinHarness-6NVAKIOB.js +5 -0
- package/dist/{twinStart-2VP545N6.js → twinStart-WIT4UVAC.js} +4 -4
- package/package.json +1 -1
- package/dist/twinHarness-OC6VQRXO.js +0 -5
package/dist/src/cli/main.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-
|
|
3
|
-
import { readManifest, writeManifest, MANIFEST_JSON, readRequiredManifest, normalizeManifestTwins } from '../../chunk-
|
|
4
|
-
import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-
|
|
2
|
+
import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-6IVXTU67.js';
|
|
3
|
+
import { readManifest, writeManifest, MANIFEST_JSON, readRequiredManifest, normalizeManifestTwins } from '../../chunk-CXGMLUZ4.js';
|
|
4
|
+
import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-FQGR7KDT.js';
|
|
5
5
|
import '../../chunk-XDU6TD4O.js';
|
|
6
6
|
import '../../chunk-CBFKZZBR.js';
|
|
7
|
-
import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, outcomeOf, readConfigTwins, scoreCountsSummary, markerFor, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-
|
|
7
|
+
import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, outcomeOf, readConfigTwins, scoreCountsSummary, markerFor, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-ANKO3RCB.js';
|
|
8
8
|
import '../../chunk-NW7HGA2K.js';
|
|
9
|
-
import { MOUNTED_TWINS, deriveAgentSlug, exitCodeFor, HostedUsageError, HostedOrchError, HostedAuthError, HostedQuotaError } from '../../chunk-
|
|
9
|
+
import { MOUNTED_TWINS, deriveAgentSlug, exitCodeFor, HostedUsageError, HostedOrchError, HostedAuthError, HostedQuotaError } from '../../chunk-BZO3YCJS.js';
|
|
10
10
|
import { TAPE_ASSERTABLE_TOOLS } from '../../chunk-C4BVTUA3.js';
|
|
11
|
-
import { seedSchema } from '../../chunk-
|
|
12
|
-
import { SLACK_CHECKS } from '../../chunk-
|
|
11
|
+
import { seedSchema } from '../../chunk-QXQAVKTE.js';
|
|
12
|
+
import { SLACK_CHECKS } from '../../chunk-2ZGVDTJC.js';
|
|
13
13
|
import { GMAIL_CHECKS } from '../../chunk-JM6VS62R.js';
|
|
14
14
|
import '../../chunk-NJ246QPJ.js';
|
|
15
15
|
import { LINEAR_CHECKS } from '../../chunk-XBT6ZLBG.js';
|
|
16
16
|
import '../../chunk-IZIZC7ZW.js';
|
|
17
17
|
import { oneOf, defineCheck, repoRef, VACUITY_SENTINEL_NUMBER, childStatePath, VACUITY_SENTINEL, statePath, templateSlots, renderCheck, checksDigest, checkPattern, checkNearMissPattern } from '../../chunk-JWJYNAWI.js';
|
|
18
|
-
import '../../chunk-
|
|
19
|
-
import { TWIN_NAME_LIST, isTwinName, createGitHubSmokeApp } from '../../chunk-
|
|
20
|
-
import '../../chunk-
|
|
21
|
-
import { isLegacyEventRow, eventSchema } from '../../chunk-
|
|
18
|
+
import '../../chunk-KIXYRPVY.js';
|
|
19
|
+
import { TWIN_NAME_LIST, isTwinName, createGitHubSmokeApp } from '../../chunk-EIUCTFQV.js';
|
|
20
|
+
import '../../chunk-CFXEETE3.js';
|
|
21
|
+
import { isLegacyEventRow, eventSchema } from '../../chunk-6KJC4BTO.js';
|
|
22
22
|
import { redactEvent, redactSecrets } from '../../chunk-SG6ZTIMT.js';
|
|
23
23
|
import { Command } from 'commander';
|
|
24
24
|
import { existsSync, readFileSync, realpathSync, statSync, constants } from 'node:fs';
|
|
@@ -422,7 +422,7 @@ var DOCS_TOPICS = [
|
|
|
422
422
|
"register",
|
|
423
423
|
"pome.json",
|
|
424
424
|
"connect",
|
|
425
|
-
// Migrated from the retired skills-setup topic
|
|
425
|
+
// Migrated from the retired skills-setup topic: wiring your own
|
|
426
426
|
// agent is now the "bring your own agent" path. ("pome-setup" / "setup"
|
|
427
427
|
// already resolve to getting-started via its "setup" keyword.)
|
|
428
428
|
"wire"
|
|
@@ -434,8 +434,8 @@ var DOCS_TOPICS = [
|
|
|
434
434
|
path: "/docs/how-pome-works",
|
|
435
435
|
keywords: ["twins", "scenarios", "runs", "scoring", "artifacts", "loop"]
|
|
436
436
|
},
|
|
437
|
-
//
|
|
438
|
-
//
|
|
437
|
+
// The Gen-1 /setup and /test-with-pome skill pages were dropped from the docs
|
|
438
|
+
// nav, and the CLI commands that pointed at them are gone. The two
|
|
439
439
|
// topic entries are gone, but their still-live keywords are MIGRATED onto the
|
|
440
440
|
// surviving replacement topics so `pome docs <kw>` keeps routing:
|
|
441
441
|
// wire → existing-agent; test-with-pome / pome-test → cli-run;
|
|
@@ -482,7 +482,7 @@ var DOCS_TOPICS = [
|
|
|
482
482
|
id: "cli",
|
|
483
483
|
title: "Command Line Interface",
|
|
484
484
|
path: "/docs/cli",
|
|
485
|
-
// "eval" migrated from the retired skills-test topic
|
|
485
|
+
// "eval" migrated from the retired skills-test topic: there is no
|
|
486
486
|
// dedicated `pome eval` docs page, and it is a distinct workflow from
|
|
487
487
|
// `pome inspect`, so it routes to the CLI reference index that documents
|
|
488
488
|
// every command rather than to a sibling command's page.
|
|
@@ -501,7 +501,7 @@ var DOCS_TOPICS = [
|
|
|
501
501
|
"default",
|
|
502
502
|
"demo task",
|
|
503
503
|
"run yours",
|
|
504
|
-
// Migrated from the retired skills-test topic
|
|
504
|
+
// Migrated from the retired skills-test topic: running tasks is
|
|
505
505
|
// how you test an agent with pome.
|
|
506
506
|
"test-with-pome",
|
|
507
507
|
"pome-test"
|
|
@@ -516,7 +516,7 @@ var DOCS_TOPICS = [
|
|
|
516
516
|
{
|
|
517
517
|
id: "cli-tasks",
|
|
518
518
|
title: "pome tasks",
|
|
519
|
-
//
|
|
519
|
+
// The M4 docs door renamed the docs.pome.sh page from
|
|
520
520
|
// /docs/cli/scenarios to /docs/cli/tasks (a redirect keeps the old URL
|
|
521
521
|
// alive), so `path` now points at the new route. The "scenarios" keyword
|
|
522
522
|
// stays so `pome docs scenarios` still resolves to this topic.
|
|
@@ -850,7 +850,7 @@ async function throwForStatus(res) {
|
|
|
850
850
|
|
|
851
851
|
// src/task/seed-verifier.ts
|
|
852
852
|
async function verifySeedWithTwin(seed) {
|
|
853
|
-
const { GitHubDomain, openGitHubCloneDatabase } = await import('../../src-
|
|
853
|
+
const { GitHubDomain, openGitHubCloneDatabase } = await import('../../src-JJNS46T6.js');
|
|
854
854
|
const db = openGitHubCloneDatabase(":memory:");
|
|
855
855
|
try {
|
|
856
856
|
new GitHubDomain(db).seed(seed);
|
|
@@ -2213,7 +2213,7 @@ var toolWasCalled = defineCheck({
|
|
|
2213
2213
|
params: { tool: toolActionName },
|
|
2214
2214
|
substrate: "tape",
|
|
2215
2215
|
// Nothing in the seed can satisfy it and only the examinee acting can, which
|
|
2216
|
-
// is the whole property: declared, never inferred from the English
|
|
2216
|
+
// is the whole property: declared, never inferred from the English.
|
|
2217
2217
|
polarity: () => "positive",
|
|
2218
2218
|
// The action name IS a caller-supplied literal hunted for in a substrate, so
|
|
2219
2219
|
// it is declared — and the engine's door-side skip matters MORE here than on
|
|
@@ -2292,7 +2292,7 @@ var GITHUB_CHECKS = [
|
|
|
2292
2292
|
// that assert about the RUN rather than the world it left behind.
|
|
2293
2293
|
noUnsupportedEndpoint,
|
|
2294
2294
|
toolNeverCalled,
|
|
2295
|
-
//
|
|
2295
|
+
// Adjacent to its prohibition for the reason the two repo-scoped
|
|
2296
2296
|
// deltas sit together above: an author reaching for one usually wants to see
|
|
2297
2297
|
// the other, and these two are the same predicate read in opposite
|
|
2298
2298
|
// directions off one closed set of actions. It is appended rather than
|
|
@@ -3887,7 +3887,7 @@ async function runEval(options) {
|
|
|
3887
3887
|
agentModel: "unknown",
|
|
3888
3888
|
agentSdk: projectIdentity?.framework ?? null,
|
|
3889
3889
|
// Eval sessions carry no client-side criteria — the cloud eval judge
|
|
3890
|
-
// owns them
|
|
3890
|
+
// owns them. Cloud's finalize schema defaults all scenario
|
|
3891
3891
|
// fields, so empty strings are accepted.
|
|
3892
3892
|
criteria: [],
|
|
3893
3893
|
taskName,
|
|
@@ -3993,7 +3993,7 @@ async function runEvalCommand(runDirArg, opts) {
|
|
|
3993
3993
|
);
|
|
3994
3994
|
} else if (err instanceof HostedOrchError && (err.status === 404 || err.status === 405)) {
|
|
3995
3995
|
console.error(
|
|
3996
|
-
"Tip: this control plane does not serve `POST /v1/eval-sessions` yet \u2014 the Pome cloud eval path
|
|
3996
|
+
"Tip: this control plane does not serve `POST /v1/eval-sessions` yet \u2014 the Pome cloud eval path is not deployed. Upgrade the control plane (or wait for the deploy). In the meantime, a hosted `pome run` still returns a cloud verdict."
|
|
3997
3997
|
);
|
|
3998
3998
|
}
|
|
3999
3999
|
process.exitCode = code;
|
|
@@ -4651,7 +4651,7 @@ var DEFAULT_AGENT_COMMAND = `node ${DEFAULT_AGENT_FILE}`;
|
|
|
4651
4651
|
var MANIFEST_SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
|
|
4652
4652
|
var MAX_UNREADABLE_PATHS_SHOWN = 5;
|
|
4653
4653
|
function readPackageVersion() {
|
|
4654
|
-
if ("0.26.
|
|
4654
|
+
if ("0.26.10".length > 0) return "0.26.10";
|
|
4655
4655
|
try {
|
|
4656
4656
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
4657
4657
|
const candidates = [
|
|
@@ -4750,7 +4750,7 @@ function createProgram() {
|
|
|
4750
4750
|
console.error(postInitMessage);
|
|
4751
4751
|
});
|
|
4752
4752
|
program.command("install").allowUnknownOption().allowExcessArguments().description(
|
|
4753
|
-
"Retired
|
|
4753
|
+
"Retired. Prints the Gen-2 wiring path: `claude mcp add \u2026 pome` + `npx skills add pome-sh/digital-twins --skill '*'`, then the pome-intake / REST-launch preflight."
|
|
4754
4754
|
).action(async () => {
|
|
4755
4755
|
const { runInstall } = await import('../../install-4OATBKG3.js');
|
|
4756
4756
|
runInstall();
|
|
@@ -4975,7 +4975,7 @@ function createProgram() {
|
|
|
4975
4975
|
process.env.POME_API_URL ?? DEFAULT_CONTROL_PLANE_URL
|
|
4976
4976
|
).option(
|
|
4977
4977
|
"--discard",
|
|
4978
|
-
"Confirm destroying a session whose run has not been graded
|
|
4978
|
+
"Confirm destroying a session whose run has not been graded",
|
|
4979
4979
|
false
|
|
4980
4980
|
).action(
|
|
4981
4981
|
async (sessionId, opts) => {
|
|
@@ -4997,7 +4997,7 @@ function createProgram() {
|
|
|
4997
4997
|
'Task markdown file or directory. Omit to run the demo task ("that was ours, run yours"): tasks/first-run-demo.md is dropped into your project on first use with runs: 5 pinned.'
|
|
4998
4998
|
).option("--agent <command>", "Agent command to run").option(
|
|
4999
4999
|
"-n, --trials <count>",
|
|
5000
|
-
"
|
|
5000
|
+
"Run <count> isolated trials of the task as ONE trial group (integer 1-20; hosted only). Default is the task config's `runs` field (capped at 20). k>1 mints sessions with a shared group id up to your plan's concurrent-twin quota (remaining trials reuse slots as earlier trials finish), runs trials at that concurrency, prints the per-trial verdict table (numeric cloud-judge scores), and exits 0 iff at least one trial completed and every completed trial passed (1: a completed trial failed; 2: nothing completed). k=1 keeps today's single-run behavior exactly."
|
|
5001
5001
|
).option("--artifacts-dir <dir>", "Directory for run artifacts", "runs").option("--hosted", "Deprecated: hosted is now the default. Flag is a no-op.").option(
|
|
5002
5002
|
"--api-url <url>",
|
|
5003
5003
|
"Control-plane base URL.",
|
|
@@ -5007,7 +5007,7 @@ function createProgram() {
|
|
|
5007
5007
|
"Override the manifest's agent.version for this run (stamped on the session/run)."
|
|
5008
5008
|
).option(
|
|
5009
5009
|
"--no-capture",
|
|
5010
|
-
"Self-host only: skip spawning the capture-server child and don't inject HTTP_PROXY/HTTPS_PROXY into the agent. Used by the CI overhead gate
|
|
5010
|
+
"Self-host only: skip spawning the capture-server child and don't inject HTTP_PROXY/HTTPS_PROXY into the agent. Used by the CI overhead gate to baseline proxy-on-vs-off latency. No-op on hosted runs."
|
|
5011
5011
|
).option(
|
|
5012
5012
|
"--local",
|
|
5013
5013
|
"Self-host: run against an in-process twin and CAPTURE a raw trace only (an audit log \u2014 no score, no verdict, no judge). A verdict comes from the cloud: run `pome eval <run-dir>` on the captured trace, or `pome login` and run against Pome cloud."
|
|
@@ -5096,7 +5096,7 @@ function createProgram() {
|
|
|
5096
5096
|
return;
|
|
5097
5097
|
}
|
|
5098
5098
|
{
|
|
5099
|
-
const { runDoctorChecks } = await import('../../checks-
|
|
5099
|
+
const { runDoctorChecks } = await import('../../checks-3LVRPHOK.js');
|
|
5100
5100
|
const { renderDoctorReport } = await import('../../render-ZQQ4UMNO.js');
|
|
5101
5101
|
const doctorReport = await runDoctorChecks({ mode: useLocal ? "full" : "hosted" });
|
|
5102
5102
|
if (!doctorReport.ok) {
|
|
@@ -5134,7 +5134,7 @@ function createProgram() {
|
|
|
5134
5134
|
taskForRuns.config.runs
|
|
5135
5135
|
);
|
|
5136
5136
|
if (k > 1) {
|
|
5137
|
-
const { runTrialGroup } = await import('../../runTrialGroup-
|
|
5137
|
+
const { runTrialGroup } = await import('../../runTrialGroup-CLJJOO4J.js');
|
|
5138
5138
|
const fileForRerun = relative(process.cwd(), file);
|
|
5139
5139
|
const rerunCommand = defaultTask ? options.trials !== void 0 ? `pome run -n ${k}` : "pome run" : `pome run ${fileForRerun && !fileForRerun.startsWith("..") ? fileForRerun : file} -n ${k}`;
|
|
5140
5140
|
const groupResult = await runTrialGroup({
|
|
@@ -5228,7 +5228,7 @@ function createProgram() {
|
|
|
5228
5228
|
process.exitCode = 5;
|
|
5229
5229
|
return;
|
|
5230
5230
|
}
|
|
5231
|
-
const { runDemo } = await import('../../runDemo-
|
|
5231
|
+
const { runDemo } = await import('../../runDemo-XO5R5QTM.js');
|
|
5232
5232
|
const result = await runDemo({
|
|
5233
5233
|
apiBase: opts.apiUrl.replace(/\/$/, ""),
|
|
5234
5234
|
dashboardBase: process.env.POME_DASHBOARD_URL ?? DEFAULT_DASHBOARD_URL,
|
|
@@ -5246,7 +5246,7 @@ function createProgram() {
|
|
|
5246
5246
|
program.command("doctor").description(
|
|
5247
5247
|
"Check the agent\u2194twin wiring: pome.json (or pome.yaml) present + valid, the local twin boots + serves, requests routed to the twin (not a hardcoded production host), egress floor active. On failure prints one named cause (file:line where knowable) + one concrete fix and exits non-zero."
|
|
5248
5248
|
).action(async () => {
|
|
5249
|
-
const { runDoctorChecks } = await import('../../checks-
|
|
5249
|
+
const { runDoctorChecks } = await import('../../checks-3LVRPHOK.js');
|
|
5250
5250
|
const { renderDoctorReport } = await import('../../render-ZQQ4UMNO.js');
|
|
5251
5251
|
const report = await runDoctorChecks();
|
|
5252
5252
|
for (const line of renderDoctorReport(report, { passNote: true })) console.error(line);
|
|
@@ -5422,7 +5422,7 @@ function createProgram() {
|
|
|
5422
5422
|
).description(
|
|
5423
5423
|
"Start a standalone twin as a long-lived foreground server (Ctrl-C to stop)"
|
|
5424
5424
|
).action(async (name, options) => {
|
|
5425
|
-
const { runTwinStartCommand } = await import('../../twinStart-
|
|
5425
|
+
const { runTwinStartCommand } = await import('../../twinStart-WIT4UVAC.js');
|
|
5426
5426
|
await runTwinStartCommand(name, options);
|
|
5427
5427
|
});
|
|
5428
5428
|
twin.command("reset").argument("[name]", "Twin name (default: github)", "github").description("Reset standalone twin state").action(async (name) => {
|
|
@@ -5461,7 +5461,7 @@ function createProgram() {
|
|
|
5461
5461
|
"Path to events.jsonl. Created if missing; appended to otherwise."
|
|
5462
5462
|
).option(
|
|
5463
5463
|
"--allow <hosts>",
|
|
5464
|
-
"
|
|
5464
|
+
"Comma-separated egress allowlist patterns (exact host or *.suffix). The floor is deny-by-default: only these hosts + loopback are tunnelled; everything else gets 403."
|
|
5465
5465
|
).option(
|
|
5466
5466
|
"--egress-out <path>",
|
|
5467
5467
|
"Path to egress.jsonl, the sidecar recording refused CONNECTs. Optional; the floor enforces regardless."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { routeInputDeclarer, bracketedQuery, integerInput, booleanInput, mountDeclaredRoute, UndeclaredInputError } from './chunk-
|
|
2
|
-
import { failureInjectionRuleSchema, loadMcpToolFixture, openTwinDatabase, createFailureInjectionStore, defineTwin, twinBuildInfo, deriveMcpToolTable, failureInjectionMiddleware, createApp, FAILURE_INJECTION_OVERRIDE_KEY, recordedRequestHeaders, UnknownToolError } from './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { routeInputDeclarer, bracketedQuery, integerInput, booleanInput, mountDeclaredRoute, UndeclaredInputError } from './chunk-IZFM7W2V.js';
|
|
2
|
+
import { failureInjectionRuleSchema, loadMcpToolFixture, openTwinDatabase, createFailureInjectionStore, defineTwin, twinBuildInfo, deriveMcpToolTable, failureInjectionMiddleware, createApp, FAILURE_INJECTION_OVERRIDE_KEY, recordedRequestHeaders, UnknownToolError } from './chunk-CFXEETE3.js';
|
|
3
|
+
import './chunk-6KJC4BTO.js';
|
|
4
4
|
import './chunk-SG6ZTIMT.js';
|
|
5
5
|
import { z, ZodError } from 'zod';
|
|
6
6
|
import { createHash, randomUUID, randomBytes } from 'node:crypto';
|
|
@@ -235,7 +235,7 @@ CREATE INDEX IF NOT EXISTS idx_payment_methods_customer ON payment_methods(custo
|
|
|
235
235
|
CREATE INDEX IF NOT EXISTS idx_payment_methods_created ON payment_methods(created);
|
|
236
236
|
CREATE INDEX IF NOT EXISTS idx_payment_methods_account_id ON payment_methods(account_id);
|
|
237
237
|
|
|
238
|
-
--
|
|
238
|
+
-- Billing tables (warm surfaces, shape tier): plain stored rows served
|
|
239
239
|
-- back in Stripe shape. No invoices table \u2014 invoices are reads-only and
|
|
240
240
|
-- nothing in the twin mints one (loud shape divergence, see FIDELITY.md).
|
|
241
241
|
|
|
@@ -709,7 +709,7 @@ var PaymentIntentsDomain = class {
|
|
|
709
709
|
last_payment_error_json: lastPaymentErrorJson
|
|
710
710
|
});
|
|
711
711
|
}
|
|
712
|
-
// ---------- update (POST /v1/payment_intents/:id
|
|
712
|
+
// ---------- update (POST /v1/payment_intents/:id) ----------
|
|
713
713
|
/**
|
|
714
714
|
* Update a non-terminal PI. Metadata merges per-key (empty/null unsets,
|
|
715
715
|
* Stripe's metadata contract). `payment_method` / `customer` are only
|
|
@@ -1555,7 +1555,7 @@ function paymentIntentJson(row) {
|
|
|
1555
1555
|
cancellation_reason: null,
|
|
1556
1556
|
// Twin row columns carry the literal Stripe values; the row type is a free
|
|
1557
1557
|
// `string`. Narrow to the upstream literal union for the type anchor only
|
|
1558
|
-
// (
|
|
1558
|
+
// (the twin faithfully emits a real upstream value), runtime unchanged.
|
|
1559
1559
|
capture_method: row.capture_method,
|
|
1560
1560
|
client_secret: row.client_secret,
|
|
1561
1561
|
confirmation_method: row.confirmation_method,
|
|
@@ -1563,9 +1563,9 @@ function paymentIntentJson(row) {
|
|
|
1563
1563
|
currency: row.currency,
|
|
1564
1564
|
customer: row.customer_id,
|
|
1565
1565
|
description: null,
|
|
1566
|
-
// Card declines
|
|
1566
|
+
// Card declines: the last failed attempt, parsed from the row.
|
|
1567
1567
|
// The stored blob is Stripe's LastPaymentError shape; narrow for the
|
|
1568
|
-
// type anchor only
|
|
1568
|
+
// type anchor only, runtime unchanged.
|
|
1569
1569
|
last_payment_error: parseJson(row.last_payment_error_json, null),
|
|
1570
1570
|
latest_charge: row.latest_charge_id,
|
|
1571
1571
|
livemode: false,
|
|
@@ -1596,8 +1596,7 @@ function chargeJson(row) {
|
|
|
1596
1596
|
crypto: {
|
|
1597
1597
|
// Upstream `Charge.PaymentMethodDetails.Crypto.{buyer_address,transaction_hash}`
|
|
1598
1598
|
// are `string | undefined`; the twin surfaces `null` pre-settlement (no
|
|
1599
|
-
// on-chain tx yet). Narrow the pre-resolution null for the type anchor only
|
|
1600
|
-
// (FDRS-454), runtime value (null) unchanged.
|
|
1599
|
+
// on-chain tx yet). Narrow the pre-resolution null for the type anchor only, runtime value (null) unchanged.
|
|
1601
1600
|
buyer_address: null,
|
|
1602
1601
|
network: "base",
|
|
1603
1602
|
token_currency: "usdc",
|
|
@@ -1629,7 +1628,7 @@ function chargeJson(row) {
|
|
|
1629
1628
|
disputed: false,
|
|
1630
1629
|
failure_balance_transaction: null,
|
|
1631
1630
|
// Twin failure columns carry Stripe's literal decline codes; the row
|
|
1632
|
-
// type is a free `string`. Narrow for the type anchor only
|
|
1631
|
+
// type is a free `string`. Narrow for the type anchor only.
|
|
1633
1632
|
failure_code: row.failure_code,
|
|
1634
1633
|
failure_message: row.failure_message,
|
|
1635
1634
|
fraud_details: {},
|
|
@@ -1653,7 +1652,7 @@ function chargeJson(row) {
|
|
|
1653
1652
|
payment_intent: row.payment_intent_id,
|
|
1654
1653
|
payment_method: row.payment_method_id,
|
|
1655
1654
|
// Stored blob is spec-faithful (built from the PM row at mint time);
|
|
1656
|
-
// narrow for the type anchor only
|
|
1655
|
+
// narrow for the type anchor only.
|
|
1657
1656
|
payment_method_details: paymentMethodDetails,
|
|
1658
1657
|
receipt_email: null,
|
|
1659
1658
|
receipt_number: null,
|
|
@@ -1684,7 +1683,7 @@ function refundJson(row) {
|
|
|
1684
1683
|
metadata: {},
|
|
1685
1684
|
payment_intent: row.payment_intent_id,
|
|
1686
1685
|
// Twin row `reason` is a free `string`; upstream `Refund.Reason` is a literal
|
|
1687
|
-
// union. Narrow for the type anchor only
|
|
1686
|
+
// union. Narrow for the type anchor only, runtime unchanged.
|
|
1688
1687
|
reason: row.reason,
|
|
1689
1688
|
receipt_number: null,
|
|
1690
1689
|
source_transfer_reversal: null,
|
|
@@ -1754,7 +1753,7 @@ function paymentMethodJson(row) {
|
|
|
1754
1753
|
livemode: false,
|
|
1755
1754
|
metadata: {},
|
|
1756
1755
|
// Twin row `type` is a free `string`; upstream `PaymentMethod.type` is a
|
|
1757
|
-
// literal union. Narrow for the type anchor only
|
|
1756
|
+
// literal union. Narrow for the type anchor only, runtime
|
|
1758
1757
|
// value ("card") unchanged.
|
|
1759
1758
|
type: row.type
|
|
1760
1759
|
};
|
|
@@ -1777,7 +1776,7 @@ function balanceTransactionJson(row) {
|
|
|
1777
1776
|
status: row.status,
|
|
1778
1777
|
// Upstream `BalanceTransaction.Type` is a literal union; the twin's ledger
|
|
1779
1778
|
// `type` column is a free `string` (carries the x402 deposit categories).
|
|
1780
|
-
// Narrow for the type anchor only
|
|
1779
|
+
// Narrow for the type anchor only, runtime value unchanged.
|
|
1781
1780
|
type: row.type
|
|
1782
1781
|
};
|
|
1783
1782
|
}
|
|
@@ -1790,7 +1789,7 @@ function eventJson(row) {
|
|
|
1790
1789
|
created: row.created,
|
|
1791
1790
|
// LIFT (ST-DIV-014): the twin stores the event payload as an opaque parsed
|
|
1792
1791
|
// JSON blob (`data.object: unknown`); upstream `Event.Data.object` is a typed
|
|
1793
|
-
// resource union. Narrow for the type anchor only
|
|
1792
|
+
// resource union. Narrow for the type anchor only, runtime unchanged.
|
|
1794
1793
|
data: parsedData,
|
|
1795
1794
|
livemode: Boolean(row.livemode),
|
|
1796
1795
|
pending_webhooks: 0,
|
|
@@ -1799,7 +1798,7 @@ function eventJson(row) {
|
|
|
1799
1798
|
idempotency_key: row.request_idempotency_key
|
|
1800
1799
|
},
|
|
1801
1800
|
// LIFT (ST-DIV-014): twin emits a free `string`; official `EventBase.type`
|
|
1802
|
-
// is the `Event.Type` literal union. Narrow for the anchor only
|
|
1801
|
+
// is the `Event.Type` literal union. Narrow for the anchor only.
|
|
1803
1802
|
type: row.type
|
|
1804
1803
|
};
|
|
1805
1804
|
}
|
|
@@ -1829,7 +1828,7 @@ function priceJson(row) {
|
|
|
1829
1828
|
const recurring = row.recurring_interval ? {
|
|
1830
1829
|
// Twin row `recurring_interval` is a free `string`; upstream
|
|
1831
1830
|
// `Price.Recurring.interval` is a literal union. Narrow for the type
|
|
1832
|
-
// anchor only
|
|
1831
|
+
// anchor only, runtime unchanged.
|
|
1833
1832
|
interval: row.recurring_interval,
|
|
1834
1833
|
interval_count: row.recurring_interval_count ?? 1,
|
|
1835
1834
|
meter: null,
|
|
@@ -2104,7 +2103,7 @@ var StripeDomain = class {
|
|
|
2104
2103
|
};
|
|
2105
2104
|
}
|
|
2106
2105
|
/**
|
|
2107
|
-
* POST /v1/payment_intents/:id
|
|
2106
|
+
* POST /v1/payment_intents/:id. The ruled retry-with-new-PM step:
|
|
2108
2107
|
* metadata merges per-key, and attaching a PM moves the card PI back to
|
|
2109
2108
|
* requires_confirmation. PM/customer resolution happens here so unknown
|
|
2110
2109
|
* ids 404 with Stripe's resource_missing before any state gate fires.
|
|
@@ -2206,7 +2205,7 @@ var StripeDomain = class {
|
|
|
2206
2205
|
* Create a refund. Returns the serialized API shape plus a canonical
|
|
2207
2206
|
* `state_delta` so the route can hand both to `respond()`.
|
|
2208
2207
|
*
|
|
2209
|
-
*
|
|
2208
|
+
* The whole flow — refund INSERT + charges.amount_refunded UPDATE
|
|
2210
2209
|
* (inside `refunds.create()`, nested as a savepoint), the negative
|
|
2211
2210
|
* refund-type balance transaction, the ledger link backfill, and the
|
|
2212
2211
|
* charge.refunded / refund.created events — commits in one better-sqlite3
|
|
@@ -2352,9 +2351,9 @@ var StripeDomain = class {
|
|
|
2352
2351
|
const { rows, hasMore, limit } = this.events.list(accountId2, input);
|
|
2353
2352
|
return serializedList(rows.map(eventJson), hasMore, limit, "/v1/events");
|
|
2354
2353
|
}
|
|
2355
|
-
// ---------- Billing (
|
|
2354
|
+
// ---------- Billing (shape tier) ----------
|
|
2356
2355
|
//
|
|
2357
|
-
// Warm surfaces per the
|
|
2356
|
+
// Warm surfaces per the ruling: stored rows served in Stripe shape,
|
|
2358
2357
|
// deliberately WITHOUT the semantic billing machine — creating a product,
|
|
2359
2358
|
// price, or subscription emits no events and mints no invoices; the
|
|
2360
2359
|
// recorder deltas stay truthful to the single-row writes.
|
|
@@ -2423,7 +2422,7 @@ var StripeDomain = class {
|
|
|
2423
2422
|
}
|
|
2424
2423
|
return subscriptionJson(row, prices);
|
|
2425
2424
|
}
|
|
2426
|
-
// Invoices are reads-only (
|
|
2425
|
+
// Invoices are reads-only (create/finalize/pay stay
|
|
2427
2426
|
// unlisted-cold) and nothing in the twin mints one, so the list is always
|
|
2428
2427
|
// empty and retrieve always 404s — loud, Stripe-shaped, documented.
|
|
2429
2428
|
retrieveInvoice(accountId2, id) {
|
|
@@ -2441,7 +2440,7 @@ var StripeDomain = class {
|
|
|
2441
2440
|
*
|
|
2442
2441
|
* Ordering is `created DESC, rowid DESC`: `created` has unix-second
|
|
2443
2442
|
* resolution, so rows minted within the same second tied and flipped
|
|
2444
|
-
* order run-to-run (the
|
|
2443
|
+
* order run-to-run (the export-race class). The insertion-order
|
|
2445
2444
|
* tiebreak keeps the export deterministic — same seed + same ops =>
|
|
2446
2445
|
* same state (test/state-export.test.ts).
|
|
2447
2446
|
*/
|
|
@@ -2632,7 +2631,7 @@ function recordDedupeEvent(c, recorder, runId, startedAt, rawBody, cached) {
|
|
|
2632
2631
|
method: c.req.method,
|
|
2633
2632
|
path: new URL(c.req.url).pathname,
|
|
2634
2633
|
request_body: rawBody === "" ? null : rawBody,
|
|
2635
|
-
//
|
|
2634
|
+
// The replay's own headers, which is where `Idempotency-Key`
|
|
2636
2635
|
// lives. Recording the dedupe outcome while hiding the key that caused it
|
|
2637
2636
|
// would leave the reason unreadable on the one row that is about it.
|
|
2638
2637
|
request_headers: recordedRequestHeaders(c),
|
|
@@ -2717,7 +2716,7 @@ function respond(c, recorder, runId, started, requestBody, status, responseBody,
|
|
|
2717
2716
|
method: c.req.method,
|
|
2718
2717
|
path: new URL(c.req.url).pathname,
|
|
2719
2718
|
request_body: requestBody,
|
|
2720
|
-
//
|
|
2719
|
+
// One shared implementation with the engine's own emit(), so
|
|
2721
2720
|
// "which headers get recorded" has a single answer across every site.
|
|
2722
2721
|
request_headers: recordedRequestHeaders(c),
|
|
2723
2722
|
// Stripe's REST routes are not declared as twin actions: no criterion asks
|
|
@@ -2952,7 +2951,7 @@ var STRIPE_ROUTES = {
|
|
|
2952
2951
|
bodyEncoding: "form",
|
|
2953
2952
|
body: CUSTOMER_FIELDS_BODY
|
|
2954
2953
|
}),
|
|
2955
|
-
//
|
|
2954
|
+
// ST-DECL-IN — NOT `LIST_QUERY`. This is the one list surface
|
|
2956
2955
|
// that does not take `created`: `GetCustomersCustomerPaymentMethods` declares
|
|
2957
2956
|
// `allow_redisplay, ending_before, expand, limit, starting_after, type` and
|
|
2958
2957
|
// nothing else, and Stripe's measured disposition is `refuse` — it publishes
|
|
@@ -4113,7 +4112,7 @@ var toolArgumentSchemas = [
|
|
|
4113
4112
|
schema: z.object({
|
|
4114
4113
|
charge: z.string().min(1),
|
|
4115
4114
|
amount: z.coerce.number().int().positive().optional(),
|
|
4116
|
-
//
|
|
4115
|
+
// Stripe's closed set, not a free string. `.optional()` is kept:
|
|
4117
4116
|
// the vendor does not require the field, and narrowing the arity as well
|
|
4118
4117
|
// as the value would refuse every refund the corpus actually makes.
|
|
4119
4118
|
reason: z.enum(STRIPE_REFUND_REASONS).optional()
|
|
@@ -4409,7 +4408,7 @@ function createStripeTwinDefinition(opts) {
|
|
|
4409
4408
|
// Session-wide middleware (the pre-port `session.use("*")` position):
|
|
4410
4409
|
// mounted by the engine BEFORE its MCP routes, so failure injection and
|
|
4411
4410
|
// idempotency cover /mcp, /mcp/call, /mcp/tools/:name exactly as the
|
|
4412
|
-
// pre-port chassis did (
|
|
4411
|
+
// pre-port chassis did (review pin: an Idempotency-Key'd MCP
|
|
4413
4412
|
// create must replay, and injected rules on MCP paths must fire).
|
|
4414
4413
|
middleware: (app, ctx) => {
|
|
4415
4414
|
app.use("*", failureInjectionMiddleware(failureInjection, {
|
|
@@ -4419,7 +4418,7 @@ function createStripeTwinDefinition(opts) {
|
|
|
4419
4418
|
}));
|
|
4420
4419
|
app.use("*", idempotencyMiddleware(db, ctx.recorder, ctx.runId));
|
|
4421
4420
|
},
|
|
4422
|
-
// Frozen pre-port body parsing on the engine-owned surfaces (
|
|
4421
|
+
// Frozen pre-port body parsing on the engine-owned surfaces (review
|
|
4423
4422
|
// review pin). Two pre-port readers existed: /admin/seed was strict
|
|
4424
4423
|
// JSON with a null fallback (null → default seed via the schema
|
|
4425
4424
|
// preprocess below), while the MCP dispatch surfaces used
|
|
@@ -4476,7 +4475,7 @@ function createStripeTwinDefinition(opts) {
|
|
|
4476
4475
|
};
|
|
4477
4476
|
},
|
|
4478
4477
|
// Frozen tape shape: stripe's pre-port recorder never saw admin
|
|
4479
|
-
// traffic — /admin/reset|seed emit no events (
|
|
4478
|
+
// traffic — /admin/reset|seed emit no events (review pin).
|
|
4480
4479
|
recorded: false,
|
|
4481
4480
|
// Frozen stripe admin-gate 403 body.
|
|
4482
4481
|
forbidden: () => forbidden("Forbidden")
|
|
@@ -4502,7 +4501,7 @@ function createStripeTwinDefinition(opts) {
|
|
|
4502
4501
|
unsupported: () => unsupported(),
|
|
4503
4502
|
errorEnvelope: stripeErrorEnvelope,
|
|
4504
4503
|
auth: {
|
|
4505
|
-
//
|
|
4504
|
+
// Frozen pins: liberal bearer parsing ON (raw token + case-insensitive
|
|
4506
4505
|
// "bearer"); sid mismatch → 403; api_keys table lookup ahead of
|
|
4507
4506
|
// provider-shaped verify + JWT; no path sid required (root mount);
|
|
4508
4507
|
// expired-vs-invalid classified by the engine and rendered through
|
|
@@ -2,9 +2,9 @@ export { GMAIL_CHECKS } from './chunk-JM6VS62R.js';
|
|
|
2
2
|
import { gmailErrorEnvelope, gmailSeedSchema, parseSeed, defaultSeedState, notFound, invalidArgument, checkFault, unsupported, validateSearchQuery, SEARCH_MAILBOX_MESSAGE_BUDGET, GmailError, parseSearchQuery, CATEGORY_LABELS, parseDate, parseSize, KNOWN_FIELDS, parseDuration, assertHasOperator } from './chunk-NJ246QPJ.js';
|
|
3
3
|
export { DEFAULT_GMAIL_AGENT_EMAIL, GmailError, SEARCH_MAILBOX_MESSAGE_BUDGET, agentPathInboxMailbox, defaultSeedState, gmailErrorEnvelope, gmailSeedSchema, loadSeedFromEnv, parseSearchQuery, parseSeed, validateSearchQuery } from './chunk-NJ246QPJ.js';
|
|
4
4
|
import './chunk-JWJYNAWI.js';
|
|
5
|
-
import { routeInputDeclarer, integerInput, booleanInput, repeatedInput, mountDeclaredRoute, UndeclaredInputError, MalformedBodyError } from './chunk-
|
|
6
|
-
import { loadMcpToolFixture, deriveMcpToolTable, defineTwin, openTwinDatabase, createApp } from './chunk-
|
|
7
|
-
import './chunk-
|
|
5
|
+
import { routeInputDeclarer, integerInput, booleanInput, repeatedInput, mountDeclaredRoute, UndeclaredInputError, MalformedBodyError } from './chunk-IZFM7W2V.js';
|
|
6
|
+
import { loadMcpToolFixture, deriveMcpToolTable, defineTwin, openTwinDatabase, createApp } from './chunk-CFXEETE3.js';
|
|
7
|
+
import './chunk-6KJC4BTO.js';
|
|
8
8
|
import './chunk-SG6ZTIMT.js';
|
|
9
9
|
import { createHash, createHmac, timingSafeEqual, randomBytes } from 'node:crypto';
|
|
10
10
|
import { z } from 'zod';
|
|
@@ -2234,14 +2234,14 @@ var mcp_tools_list_meta_default = {
|
|
|
2234
2234
|
derivation: "the upstream golden in full \u2014 all 13 tools, no subtraction. Produced by scripts/adopt-upstream-mcp-fixture.ts from fixtures/mcp-tools-list/gmail.raw.json at rawFileSha256 fd2b12868289aee89798c218a7ea2307fc475935d3d912c2a3c35b5d75ae21ee, whose bytes this file copies verbatim."
|
|
2235
2235
|
},
|
|
2236
2236
|
notes: [
|
|
2237
|
-
"
|
|
2237
|
+
"These bytes are Google's, adopted rather than transcribed. The fixture that shipped before this one was the same endpoint read on 2026-07-20 and was never refreshed, so the twin advertised a seventeen-day-old listing and pome-cloud's mcp_diff reported 34 findings across 11 tools \u2014 all of them the vendor moving, none of them a twin defect. Produced by scripts/adopt-upstream-mcp-fixture.ts; `npm run gate:mcp-fixture -w @pome-sh/twin-gmail` re-derives and diffs.",
|
|
2238
2238
|
"13 tools, which is every tool the capture carries. Unlike twin-slack's adoption there is no suppression list: nothing here is withheld, so raw.json is byte-identical to fixtures/mcp-tools-list/gmail.raw.json and the two shas agree.",
|
|
2239
2239
|
"Descriptions, schemas and annotations are the capture's verbatim. Three of its claims are behavioural and were implemented in the same change rather than merely served: Message.bccRecipients, Label.messagesTotal/messagesUnread, and a list_labels that answers with ALL labels \u2014 the July listing said 'all user-defined labels' and the twin returned exactly those.",
|
|
2240
2240
|
"list_labels takes no arguments in this listing. The July capture declared pageSize/pageToken and the twin paginated; Google has since removed both, along with nextPageToken from the response, so the twin answers every label in one page. LIMITS.md's MCP page-size row no longer names this tool.",
|
|
2241
2241
|
"Authenticated tools/call success envelopes were unavailable; the reconstructed shapes live in mcp-tools-call.representative.json and the live unauthenticated error envelope in mcp-tools-call-unauth-error.raw.json.",
|
|
2242
2242
|
"initialize returned protocolVersion=2025-03-26 (mcp-initialize.raw.json)."
|
|
2243
2243
|
],
|
|
2244
|
-
canonicalFileSha256: "
|
|
2244
|
+
canonicalFileSha256: "d9a7348833d43a964d541d57336f571f93f7c55d1b43b2b773e9307443b73bf9",
|
|
2245
2245
|
files: {
|
|
2246
2246
|
raw: "mcp-tools-list.raw.json",
|
|
2247
2247
|
canonical: "mcp-tools-list.canonical.json"
|
|
@@ -2514,7 +2514,7 @@ var implementations = {
|
|
|
2514
2514
|
// `threads` above is the PAGE; this is the whole match set, which is
|
|
2515
2515
|
// why the count is exact rather than an estimate. Google documents the
|
|
2516
2516
|
// field as a lower bound, so an exact count satisfies the contract —
|
|
2517
|
-
// and the advertised type is int64-as-STRING, not a number
|
|
2517
|
+
// and the advertised type is int64-as-STRING, not a number.
|
|
2518
2518
|
// Unconditional: it is the answer to "how many matched", and 0 matches
|
|
2519
2519
|
// is an answer. Emitting it only when non-zero would make an absent
|
|
2520
2520
|
// field mean two different things.
|
|
@@ -2545,7 +2545,7 @@ var implementations = {
|
|
|
2545
2545
|
// takes no page arguments and offers no nextPageToken back. The July
|
|
2546
2546
|
// listing this twin used to serve said "all user-defined labels", which is
|
|
2547
2547
|
// what `listUserLabels` returns and what this handler used to call; the
|
|
2548
|
-
// widening is Google's and
|
|
2548
|
+
// widening is Google's and the twin follows it.
|
|
2549
2549
|
handler: (domain, _args, ctx) => ({
|
|
2550
2550
|
labels: domain.labels(identityFromSession(ctx.session).email).map(labelResult)
|
|
2551
2551
|
})
|
|
@@ -2658,7 +2658,7 @@ function messageResult(message, format) {
|
|
|
2658
2658
|
sender: message.from,
|
|
2659
2659
|
toRecipients: message.to,
|
|
2660
2660
|
ccRecipients: message.cc,
|
|
2661
|
-
//
|
|
2661
|
+
// The adopted listing declares it on Message, so it is served
|
|
2662
2662
|
// wherever the other two recipient lists are — `get_message`, `get_thread`
|
|
2663
2663
|
// and the threads `search_threads` nests.
|
|
2664
2664
|
bccRecipients: message.bcc
|
|
@@ -2688,7 +2688,7 @@ function labelResult(label2) {
|
|
|
2688
2688
|
labelId: label2.id,
|
|
2689
2689
|
name: label2.name,
|
|
2690
2690
|
...Object.keys(color).length > 0 ? { color } : {},
|
|
2691
|
-
//
|
|
2691
|
+
// The August listing declares the message counters beside the
|
|
2692
2692
|
// thread ones. The domain has counted both all along — the REST
|
|
2693
2693
|
// serializer already published all four — so this was a projection that
|
|
2694
2694
|
// dropped two fields, not a measurement the twin could not make.
|