@remits/remits-cli 0.1.135 → 0.1.136
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/index.js
CHANGED
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
- L22 Runtime Bootstrap And Shared State
|
|
7
7
|
- L119 Sessions, Account Resolution, And Production Guards
|
|
8
8
|
- L603 Local State, Workspaces, And Verification Evidence
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
9
|
+
- L2624 Account Repos, Guide Sync, And Platform Repo
|
|
10
|
+
- L3432 Component Discovery And HTTP Logging
|
|
11
|
+
- L4073 Skill Delivery And TOC Resolution
|
|
12
|
+
- L4383 Auth And Component Staging
|
|
13
|
+
- L4998 Component Summaries, Status, And Sync Gates
|
|
14
|
+
- L7067 Branches, Promotion, Commit, And Test Runs
|
|
15
|
+
- L8750 Tokens, Tools, Verification, And Config
|
|
16
|
+
- L10177 Service Dashboard And WebSocket Listener
|
|
17
|
+
- L12298 Agent And Ticket Workflows
|
|
18
|
+
- L15888 Help, Auto Update, And Command Dispatch
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
/*
|
|
@@ -626,6 +626,7 @@ function localStatePaths(cwd) {
|
|
|
626
626
|
toolResponsesDir: path.join(actorDir, 'tool-responses'),
|
|
627
627
|
verificationDir: path.join(actorDir, 'verification'),
|
|
628
628
|
diagnosticsDir: path.join(actorDir, 'diagnostics'),
|
|
629
|
+
evidenceFile: path.join(actorDir, 'evidence.jsonl'),
|
|
629
630
|
activeVerificationFile: path.join(actorDir, 'verification', 'active'),
|
|
630
631
|
activeVerificationContextsFile: path.join(actorDir, 'verification', 'active-contexts.json'),
|
|
631
632
|
currentSessionFile: path.join(actorDir, 'current-session.txt'),
|
|
@@ -1999,9 +2000,145 @@ async function printVerificationRunProbe(api, cwd, session, accountId, envelopeI
|
|
|
1999
2000
|
return result;
|
|
2000
2001
|
}
|
|
2001
2002
|
|
|
2003
|
+
/**
|
|
2004
|
+
* The always-on evidence trail.
|
|
2005
|
+
*
|
|
2006
|
+
* <p>One world-stamped line per evidence-producing command, written whether or not any verification envelope
|
|
2007
|
+
* exists. This is the answer to "what have I actually run, and in which world?" - the question agents were
|
|
2008
|
+
* opening envelopes to answer, and an envelope is a far heavier instrument than that question needs. It is
|
|
2009
|
+
* per-actor, so two agents in one checkout never read each other's trail, and it is append-only with a bounded
|
|
2010
|
+
* tail so it cannot grow without limit.</p>
|
|
2011
|
+
*
|
|
2012
|
+
* <p>Recording is deliberately decision-free: there is no flag to remember, no state to start, and nothing an
|
|
2013
|
+
* agent can fail to satisfy.</p>
|
|
2014
|
+
*/
|
|
2015
|
+
const EVIDENCE_TRAIL_MAX_LINES = 2000;
|
|
2016
|
+
|
|
2017
|
+
function recordEvidenceEntry(cwd, packet, context = {}) {
|
|
2018
|
+
try {
|
|
2019
|
+
const paths = ensureLocalState(cwd);
|
|
2020
|
+
const world = (packet && packet.world && typeof packet.world === 'object') ? packet.world : {};
|
|
2021
|
+
const hasSuccess = packet && Object.prototype.hasOwnProperty.call(packet, 'success');
|
|
2022
|
+
const entry = {
|
|
2023
|
+
ts: new Date().toISOString(),
|
|
2024
|
+
type: packet && packet.type || 'unknown',
|
|
2025
|
+
claim: packet && packet.claim || null,
|
|
2026
|
+
success: hasSuccess ? packet.success : true,
|
|
2027
|
+
pending: packet && packet.pending === true || (hasSuccess && packet.success === null),
|
|
2028
|
+
world: {
|
|
2029
|
+
repoAccountId: world.repoAccountId != null ? world.repoAccountId : context.accountId || null,
|
|
2030
|
+
executionAccountId: world.executionAccountId != null ? world.executionAccountId : (world.accountId != null ? world.accountId : null),
|
|
2031
|
+
targetAccountId: world.targetAccountId != null ? world.targetAccountId : null,
|
|
2032
|
+
dataMode: world.dataMode || context.dataMode || null,
|
|
2033
|
+
branchName: world.branchName || world.gitBranch || context.branchName || null,
|
|
2034
|
+
componentBranch: world.componentBranch || world.variantBranch || null,
|
|
2035
|
+
workspace: world.workspace !== undefined ? world.workspace : (context.workspace !== undefined ? context.workspace : null),
|
|
2036
|
+
sourceLayer: world.sourceLayer || null,
|
|
2037
|
+
laneContentHash: world.laneContentHash || world.stagedOverlayHash || null,
|
|
2038
|
+
host: world.host || context.baseUrl || null
|
|
2039
|
+
},
|
|
2040
|
+
ref: {
|
|
2041
|
+
packetId: packet && packet.packetId || null,
|
|
2042
|
+
taskId: (packet && packet.test && packet.test.taskId) || (packet && packet.status && packet.status.taskId) || null,
|
|
2043
|
+
callId: (packet && packet.tool && packet.tool.callId) || null,
|
|
2044
|
+
responseFile: (packet && packet.tool && packet.tool.responseFile) || null
|
|
2045
|
+
},
|
|
2046
|
+
// Present when an envelope happened to be active. Never required, and never something to chase.
|
|
2047
|
+
envelopeId: context.envelopeId || null,
|
|
2048
|
+
claims: Array.isArray(packet && packet.claims) ? packet.claims : undefined
|
|
2049
|
+
};
|
|
2050
|
+
fs.appendFileSync(paths.evidenceFile, JSON.stringify(entry) + '\n');
|
|
2051
|
+
trimEvidenceTrail(paths.evidenceFile);
|
|
2052
|
+
return entry;
|
|
2053
|
+
} catch (_) {
|
|
2054
|
+
// A trail write must never fail the command it is describing.
|
|
2055
|
+
return null;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
function evidenceOutcome(row) {
|
|
2060
|
+
if (row && (row.pending === true || row.success === null)) return 'pending';
|
|
2061
|
+
return row && row.success === false ? 'failed' : 'ok';
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
function evidenceOutcomeLabel(row) {
|
|
2065
|
+
const outcome = evidenceOutcome(row);
|
|
2066
|
+
if (outcome === 'failed') return 'FAILED ';
|
|
2067
|
+
if (outcome === 'pending') return 'PENDING ';
|
|
2068
|
+
return '';
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
function trimEvidenceTrail(file) {
|
|
2072
|
+
try {
|
|
2073
|
+
const lines = fs.readFileSync(file, 'utf8').split('\n').filter(Boolean);
|
|
2074
|
+
if (lines.length <= EVIDENCE_TRAIL_MAX_LINES) return;
|
|
2075
|
+
atomicWriteFile(file, lines.slice(lines.length - EVIDENCE_TRAIL_MAX_LINES).join('\n') + '\n');
|
|
2076
|
+
} catch (_) { /* best effort */ }
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
function readEvidenceTrail(cwd, limit = 50) {
|
|
2080
|
+
try {
|
|
2081
|
+
const paths = localStatePaths(cwd);
|
|
2082
|
+
if (!fs.existsSync(paths.evidenceFile)) return [];
|
|
2083
|
+
const lines = fs.readFileSync(paths.evidenceFile, 'utf8').split('\n').filter(Boolean);
|
|
2084
|
+
return lines.slice(Math.max(0, lines.length - limit)).map((line) => {
|
|
2085
|
+
try { return JSON.parse(line); } catch (_) { return null; }
|
|
2086
|
+
}).filter(Boolean);
|
|
2087
|
+
} catch (_) {
|
|
2088
|
+
return [];
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
/**
|
|
2093
|
+
* WHERE a command ran: accounts, lane, branch, workspace. Deliberately NOT `sourceLayer` or
|
|
2094
|
+
* `laneContentHash` - those legitimately differ between two commands in the same world (a stage is `staged`,
|
|
2095
|
+
* the test that follows resolves `db`), so keying the grouping on them split one world into several and made
|
|
2096
|
+
* two entries from the same context look like two different places. They belong on the entry.
|
|
2097
|
+
*/
|
|
2098
|
+
function describeEvidenceWorld(world) {
|
|
2099
|
+
const w = world || {};
|
|
2100
|
+
const accounts = w.executionAccountId && String(w.executionAccountId) !== String(w.repoAccountId)
|
|
2101
|
+
? 'account ' + w.repoAccountId + ' -> runs as ' + w.executionAccountId
|
|
2102
|
+
: 'account ' + (w.repoAccountId == null ? '?' : w.repoAccountId);
|
|
2103
|
+
return [
|
|
2104
|
+
accounts,
|
|
2105
|
+
w.targetAccountId && String(w.targetAccountId) !== String(w.executionAccountId) ? 'targets ' + w.targetAccountId : null,
|
|
2106
|
+
w.dataMode ? w.dataMode + ' lane' : null,
|
|
2107
|
+
w.branchName ? 'branch ' + w.branchName : null,
|
|
2108
|
+
w.componentBranch ? 'components ' + w.componentBranch : null,
|
|
2109
|
+
'ws:' + (w.workspace || 'shared')
|
|
2110
|
+
].filter(Boolean).join(' · ');
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
function claimIdsFromFlags(flags) {
|
|
2114
|
+
return []
|
|
2115
|
+
.concat((flags && flags.claim) || [])
|
|
2116
|
+
.concat((flags && flags.claims) || [])
|
|
2117
|
+
.filter(Boolean)
|
|
2118
|
+
.flatMap((value) => String(value).split(','))
|
|
2119
|
+
.map((value) => value.trim())
|
|
2120
|
+
.filter(Boolean);
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
function stampPacketClaims(packet, flags) {
|
|
2124
|
+
const claims = claimIdsFromFlags(flags);
|
|
2125
|
+
if (!claims.length) return packet;
|
|
2126
|
+
if (!Array.isArray(packet.evidenceCategories)) packet.evidenceCategories = [];
|
|
2127
|
+
claims.forEach((claim) => {
|
|
2128
|
+
if (!packet.evidenceCategories.includes(claim)) packet.evidenceCategories.push(claim);
|
|
2129
|
+
});
|
|
2130
|
+
packet.claims = claims;
|
|
2131
|
+
return packet;
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2002
2134
|
async function appendVerificationPacket(api, cwd, session, accountId, flags, packet, options = {}) {
|
|
2003
2135
|
const context = activeVerificationContext(cwd, flags, session, accountId);
|
|
2004
2136
|
const envelopeId = verificationEnvelopeIdForCommand(cwd, flags, context);
|
|
2137
|
+
// The trail is written FIRST and unconditionally. Evidence recording must not depend on an agent having
|
|
2138
|
+
// remembered to start anything: an envelope is an optional verdict on top of this, never the thing that
|
|
2139
|
+
// makes a command's world durable.
|
|
2140
|
+
stampPacketClaims(packet, flags);
|
|
2141
|
+
recordEvidenceEntry(cwd, packet, Object.assign({}, context, { accountId, envelopeId }));
|
|
2005
2142
|
if (!envelopeId) return null;
|
|
2006
2143
|
const finalPacket = Object.assign({
|
|
2007
2144
|
packetId: crypto.randomUUID(),
|
|
@@ -2067,7 +2204,7 @@ function printVerificationSummaryLine(env) {
|
|
|
2067
2204
|
const health = env.health ? ' health=' + env.health : '';
|
|
2068
2205
|
const failures = env.currentFailureCount ? ' currentFailures=' + env.currentFailureCount : (env.failedCount ? ' failed=' + env.failedCount : '');
|
|
2069
2206
|
const required = ' required=' + (env.satisfiedCount || 0) + '/' + (env.requiredCount || 0);
|
|
2070
|
-
const noManifest = env.noRequiredEvidence ? '
|
|
2207
|
+
const noManifest = env.noRequiredEvidence ? ' evidence-log' : '';
|
|
2071
2208
|
const stale = env.staleCount ? ' stale=' + env.staleCount : '';
|
|
2072
2209
|
const changed = env.requirementsChangedAfterEvidence ? ' requirements-changed' : '';
|
|
2073
2210
|
const lane = [env.branchName || 'unknown-branch', env.workspace ? 'ws:' + env.workspace : 'shared', env.dataMode || null, env.sourceLayer || null]
|
|
@@ -2084,7 +2221,7 @@ function printVerificationEnvelope(envelope, fallbackEnvelopeId) {
|
|
|
2084
2221
|
const evaluation = envelope.evaluation || {};
|
|
2085
2222
|
if (evaluation.health) console.log('Health:', evaluation.health);
|
|
2086
2223
|
if (evaluation.noRequiredEvidence) {
|
|
2087
|
-
console.log('Required evidence: none declared - evidence
|
|
2224
|
+
console.log('Required evidence: none declared - evidence log only; no verdict is outstanding.');
|
|
2088
2225
|
} else {
|
|
2089
2226
|
console.log('Required evidence:', (evaluation.satisfiedCount || 0) + '/' + (evaluation.requiredCount || 0));
|
|
2090
2227
|
}
|
|
@@ -2143,7 +2280,7 @@ function compactVerificationEnvelope(envelope, fallbackEnvelopeId) {
|
|
|
2143
2280
|
const nextActions = [];
|
|
2144
2281
|
|
|
2145
2282
|
if (evaluation.noRequiredEvidence) {
|
|
2146
|
-
nextActions.push('
|
|
2283
|
+
nextActions.push('No verdict was requested. Leave this as an evidence log, or add `verify claim <id> --text "..."` only if someone needs a checkable verdict.');
|
|
2147
2284
|
}
|
|
2148
2285
|
if (failures.length) {
|
|
2149
2286
|
nextActions.push('Inspect and replace the current failing evidence packet(s).');
|
|
@@ -2227,14 +2364,27 @@ function printEnvelopeWarnings(envelope) {
|
|
|
2227
2364
|
console.log('Envelope warnings:');
|
|
2228
2365
|
warnings.forEach((warning) => {
|
|
2229
2366
|
console.log('- ' + (warning.message || warning.code || JSON.stringify(warning)));
|
|
2367
|
+
if (warning.command) console.log(' ' + warning.command);
|
|
2230
2368
|
if (Array.isArray(warning.envelopes) && warning.envelopes.length) {
|
|
2231
2369
|
warning.envelopes.forEach((env) => {
|
|
2232
|
-
|
|
2370
|
+
// Say whether the duplicate is in THIS world. A restart in a genuinely different lane or branch is
|
|
2371
|
+
// sometimes exactly right; a second envelope for the same goal in the same world is the loop.
|
|
2372
|
+
const world = env.world && typeof env.world === 'object'
|
|
2373
|
+
? Object.keys(env.world).map((key) => key + '=' + env.world[key]).join(' ')
|
|
2374
|
+
: '';
|
|
2375
|
+
console.log(' ' + (env.envelopeId || '(no id)') + (env.status ? ' ' + env.status : '') +
|
|
2376
|
+
(env.sameWorld === true ? ' [same world]' : (world ? ' [' + world + ']' : '')));
|
|
2233
2377
|
});
|
|
2378
|
+
console.log(' Continue one of those with `remits-cli verify use <id>`, or supersede it once this one supersedes its goal.');
|
|
2234
2379
|
}
|
|
2235
2380
|
});
|
|
2236
2381
|
}
|
|
2237
2382
|
|
|
2383
|
+
function manifestClaims(manifest) {
|
|
2384
|
+
const claims = manifest && manifest.claims;
|
|
2385
|
+
return Array.isArray(claims) ? claims.filter(Boolean) : [];
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2238
2388
|
function manifestRequiredEvidence(manifest = {}) {
|
|
2239
2389
|
const required = [];
|
|
2240
2390
|
if (Array.isArray(manifest.requiredEvidence)) required.push(...manifest.requiredEvidence);
|
|
@@ -9565,10 +9715,16 @@ async function verifyCommand(flags, subcommand) {
|
|
|
9565
9715
|
if (flags.manifest || flags.file) {
|
|
9566
9716
|
manifest = parseManifestFile(flags.manifest || flags.file);
|
|
9567
9717
|
}
|
|
9568
|
-
|
|
9718
|
+
// PROD only, and framed as risk rather than as an unmet obligation. An envelope with no contract is an
|
|
9719
|
+
// evidence log, which is the normal and complete mode; warning about it on every lane taught agents that
|
|
9720
|
+
// their own record-keeping was an exam they were failing, and they responded by starting it over.
|
|
9721
|
+
if (dataMode === 'prod' && !manifestRequiredEvidence(manifest).length && !manifestClaims(manifest).length &&
|
|
9722
|
+
!flagEnabled(flags['no-contract'])) {
|
|
9569
9723
|
console.error('');
|
|
9570
|
-
console.error('
|
|
9571
|
-
console.error('
|
|
9724
|
+
console.error('Note: this envelope records PRODUCTION-data evidence with no acceptance contract.');
|
|
9725
|
+
console.error('That is fine for investigation. Before destructive or irreversible production work, name what');
|
|
9726
|
+
console.error('must be true so the result is checkable by someone else:');
|
|
9727
|
+
console.error(' remits-cli verify claim <id> --text "what must be true" [--test "<suite>"]');
|
|
9572
9728
|
console.error('');
|
|
9573
9729
|
}
|
|
9574
9730
|
let statusResponse = null;
|
|
@@ -9598,12 +9754,17 @@ async function verifyCommand(flags, subcommand) {
|
|
|
9598
9754
|
ticketId: flags.ticket,
|
|
9599
9755
|
account: collectVerificationAccount(cwd, accountId, baseUrl, dataMode),
|
|
9600
9756
|
source,
|
|
9601
|
-
manifest
|
|
9757
|
+
manifest,
|
|
9758
|
+
noContract: flagEnabled(flags['no-contract']) || undefined
|
|
9602
9759
|
});
|
|
9603
9760
|
const envelope = response.envelope;
|
|
9604
9761
|
writeLocalVerificationEnvelope(cwd, envelope);
|
|
9605
9762
|
writeActiveVerificationEnvelope(cwd, envelope.envelopeId, activeContext);
|
|
9606
9763
|
console.log('Verification envelope started:', envelope.envelopeId);
|
|
9764
|
+
if (!manifestRequiredEvidence(manifest).length && !manifestClaims(manifest).length) {
|
|
9765
|
+
console.log('Mode: evidence log (no acceptance contract asked for). Commands attach world-stamped evidence;');
|
|
9766
|
+
console.log(' nothing is outstanding. Add `verify claim <id> --text "..."` only if someone needs a verdict.');
|
|
9767
|
+
}
|
|
9607
9768
|
printLocalCommandContext(cwd, flags, { accountId, branchName, workspace, dataMode });
|
|
9608
9769
|
printLocalStateWarnings(cwd, flags);
|
|
9609
9770
|
console.log('Target:', checkoutWorldLine + ', dataMode=' + dataMode +
|
|
@@ -9683,6 +9844,40 @@ async function verifyCommand(flags, subcommand) {
|
|
|
9683
9844
|
return envelope;
|
|
9684
9845
|
}
|
|
9685
9846
|
|
|
9847
|
+
if (sub === 'claim' || sub === 'claims') {
|
|
9848
|
+
const claimId = flags.id || (flags._ && flags._[2]);
|
|
9849
|
+
const text = flags.text || flags.claim || flags.summary || flags.note;
|
|
9850
|
+
if (!claimId) {
|
|
9851
|
+
throw new Error('Usage: remits-cli verify claim <id> --text "what must be true" [--test "<suite>"] [--packet-type <type>]');
|
|
9852
|
+
}
|
|
9853
|
+
const claim = { id: String(claimId) };
|
|
9854
|
+
if (text) claim.text = String(text);
|
|
9855
|
+
// A claim may name the shape of evidence that proves it, so one line of contract can bind to a suite
|
|
9856
|
+
// instead of needing a second parallel requiredEvidence list kept in sync by hand.
|
|
9857
|
+
const suite = flags.test || flags.suite;
|
|
9858
|
+
if (suite) {
|
|
9859
|
+
claim.packetType = 'test_run';
|
|
9860
|
+
claim.suite = String(suite);
|
|
9861
|
+
if (flags.case || flags.cases) {
|
|
9862
|
+
claim.cases = [].concat(flags.case || []).concat(flags.cases || [])
|
|
9863
|
+
.flatMap((value) => String(value).split(',')).map((value) => value.trim()).filter(Boolean);
|
|
9864
|
+
}
|
|
9865
|
+
} else if (flags['packet-type'] || flags.packetType) {
|
|
9866
|
+
claim.packetType = String(flags['packet-type'] || flags.packetType);
|
|
9867
|
+
}
|
|
9868
|
+
const response = await postVerificationCommand(api, cwd, session, accountId, 'claim', { envelopeId, claim });
|
|
9869
|
+
writeLocalVerificationEnvelope(cwd, response.envelope);
|
|
9870
|
+
const acceptance = (response.envelope || {}).acceptance || {};
|
|
9871
|
+
console.log('Claim recorded on envelope ' + envelopeId + ': ' + claim.id);
|
|
9872
|
+
console.log('Contract now requires ' + (acceptance.requiredEvidence || []).length + ' item(s).');
|
|
9873
|
+
console.log('Prove it by adding --claim ' + claim.id + ' to the command that demonstrates it, e.g.');
|
|
9874
|
+
console.log(' remits-cli verify test --test "<suite>" --claim ' + claim.id);
|
|
9875
|
+
console.log(' remits-cli verify attach --claim ' + claim.id + ' --note "what you observed"');
|
|
9876
|
+
printAcceptanceWarnings(response.envelope);
|
|
9877
|
+
printEnvelopeWarnings(response.envelope);
|
|
9878
|
+
return response.envelope;
|
|
9879
|
+
}
|
|
9880
|
+
|
|
9686
9881
|
if (sub === 'attach') {
|
|
9687
9882
|
const artifacts = [];
|
|
9688
9883
|
let type = 'manual_observation';
|
|
@@ -9719,7 +9914,7 @@ async function verifyCommand(flags, subcommand) {
|
|
|
9719
9914
|
artifacts,
|
|
9720
9915
|
evidenceCategories
|
|
9721
9916
|
};
|
|
9722
|
-
const response = await appendVerificationPacket(api, cwd, session, accountId, { 'verify-envelope': envelopeId }, packet);
|
|
9917
|
+
const response = await appendVerificationPacket(api, cwd, session, accountId, Object.assign({}, flags, { 'verify-envelope': envelopeId }), packet);
|
|
9723
9918
|
console.log('Evidence attached:', (response.packet || packet).packetId);
|
|
9724
9919
|
return response;
|
|
9725
9920
|
}
|
|
@@ -9730,7 +9925,9 @@ async function verifyCommand(flags, subcommand) {
|
|
|
9730
9925
|
const packet = {
|
|
9731
9926
|
type: sub === 'browser-start' ? 'browser_session' : (sub === 'browser-snapshot' ? 'browser_snapshot' : 'browser_step'),
|
|
9732
9927
|
success: !flagEnabled(flags.failed),
|
|
9733
|
-
claim
|
|
9928
|
+
// `--claim` now names a declared acceptance claim id, so the free-text label for a browser step is
|
|
9929
|
+
// `--label`. Reading both from one flag made the id double as prose and the prose double as an id.
|
|
9930
|
+
claim: flags.label || flags.text || action,
|
|
9734
9931
|
world: buildCommandWorld(null, { accountId, dataMode, branchName, workspace, host: normalizeBaseUrl(baseUrl) }),
|
|
9735
9932
|
browser: {
|
|
9736
9933
|
action,
|
|
@@ -9743,7 +9940,7 @@ async function verifyCommand(flags, subcommand) {
|
|
|
9743
9940
|
evidenceCategories: [sub, action === 'upload' ? 'browser_session.actual_upload' : null, action === 'click' ? 'browser_session.actual_clicks' : null]
|
|
9744
9941
|
.filter(Boolean)
|
|
9745
9942
|
};
|
|
9746
|
-
const response = await appendVerificationPacket(api, cwd, session, accountId, { 'verify-envelope': envelopeId }, packet);
|
|
9943
|
+
const response = await appendVerificationPacket(api, cwd, session, accountId, Object.assign({}, flags, { 'verify-envelope': envelopeId }), packet);
|
|
9747
9944
|
console.log('Browser evidence attached:', (response.packet || packet).packetId);
|
|
9748
9945
|
return response;
|
|
9749
9946
|
}
|
|
@@ -14708,23 +14905,57 @@ function slimActivitySmell(smell) {
|
|
|
14708
14905
|
testName: s.testName || null,
|
|
14709
14906
|
branchName: s.branchName || null,
|
|
14710
14907
|
workspace: s.workspace || null,
|
|
14908
|
+
packetCount: s.packetCount == null ? null : s.packetCount,
|
|
14909
|
+
requiredCount: s.requiredCount == null ? null : s.requiredCount,
|
|
14910
|
+
openCount: s.openCount == null ? null : s.openCount,
|
|
14911
|
+
command: s.command || null,
|
|
14711
14912
|
updatedAt: formatTime(s.updatedAtMs || s.updatedAt || s.at || s.createdAt)
|
|
14712
14913
|
};
|
|
14713
14914
|
}
|
|
14714
14915
|
|
|
14916
|
+
/**
|
|
14917
|
+
* The next COMMAND, not the smell restated. This list previously mapped each signal to its own summary
|
|
14918
|
+
* sentence, so "Next actions" contained no action; and it filtered on severity <= 2, which permanently
|
|
14919
|
+
* excluded `no_required_evidence` - the one signal that explains why an envelope never closes.
|
|
14920
|
+
* A signal that knows its own fix is actionable at any severity.
|
|
14921
|
+
*/
|
|
14922
|
+
function buildActivityNextActions(smells) {
|
|
14923
|
+
const seen = new Set();
|
|
14924
|
+
return (smells || [])
|
|
14925
|
+
.filter((smell) => smell && (smell.command || smellSeverityRank(smell) <= 2))
|
|
14926
|
+
.sort((left, right) => {
|
|
14927
|
+
const command = (right.command ? 1 : 0) - (left.command ? 1 : 0);
|
|
14928
|
+
if (command) return command;
|
|
14929
|
+
return smellSeverityRank(left) - smellSeverityRank(right);
|
|
14930
|
+
})
|
|
14931
|
+
.map((smell) => {
|
|
14932
|
+
const title = smell.title || smell.envelopeSummary || smell.testName ||
|
|
14933
|
+
(Array.isArray(smell.workspaces) ? smell.workspaces.join(', ') : null);
|
|
14934
|
+
return {
|
|
14935
|
+
type: smell.type || 'signal',
|
|
14936
|
+
severity: smell.severity || 'info',
|
|
14937
|
+
why: (title ? title + ' — ' : '') + (smell.summary || 'inspect this signal'),
|
|
14938
|
+
command: smell.command || null
|
|
14939
|
+
};
|
|
14940
|
+
})
|
|
14941
|
+
.filter((action) => {
|
|
14942
|
+
// Dedupe on the COMMAND when there is one: two different signals about one envelope that resolve to
|
|
14943
|
+
// the same next move are one next move.
|
|
14944
|
+
const key = action.command ? 'cmd|' + action.command : action.type + '|' + action.why;
|
|
14945
|
+
if (seen.has(key)) return false;
|
|
14946
|
+
seen.add(key);
|
|
14947
|
+
return true;
|
|
14948
|
+
})
|
|
14949
|
+
.slice(0, 6);
|
|
14950
|
+
}
|
|
14951
|
+
|
|
14715
14952
|
function compactActivityInspect(response) {
|
|
14716
14953
|
const counts = response.counts || {};
|
|
14717
14954
|
const smells = sortedActivitySmells(response.smells);
|
|
14718
14955
|
const lanes = Array.isArray(response.lanes) ? response.lanes : [];
|
|
14719
14956
|
const envelopes = Array.isArray(response.envelopes) ? response.envelopes : [];
|
|
14720
14957
|
const testRuns = Array.isArray(response.testRuns) ? response.testRuns : [];
|
|
14721
|
-
const nextActions = smells
|
|
14722
|
-
.filter((smell) => smellSeverityRank(smell) <= 2)
|
|
14723
|
-
.slice(0, 5)
|
|
14724
|
-
.map((smell) => {
|
|
14725
|
-
const title = smell.title || smell.envelopeSummary || smell.testName;
|
|
14726
|
-
return (smell.type || 'signal') + (title ? ' (' + title + ')' : '') + ': ' + (smell.summary || 'inspect this signal');
|
|
14727
|
-
});
|
|
14958
|
+
const nextActions = buildActivityNextActions(smells);
|
|
14728
14959
|
|
|
14729
14960
|
return {
|
|
14730
14961
|
success: response.success,
|
|
@@ -14809,7 +15040,14 @@ function printActivityInspectSummary(response) {
|
|
|
14809
15040
|
(counts.lanes || 0) + ' lane(s), ' +
|
|
14810
15041
|
(counts.verificationEnvelopes || 0) + ' envelope(s), ' +
|
|
14811
15042
|
(counts.testRuns || 0) + ' test run(s), ' +
|
|
14812
|
-
(counts.corpusResults || 0) + ' corpus result(s)'
|
|
15043
|
+
(counts.corpusResults || 0) + ' corpus result(s)' +
|
|
15044
|
+
(counts.distinctStagedEntries != null && counts.distinctStagedEntries !== counts.stagedEntries
|
|
15045
|
+
? ', ' + counts.stagedEntries + ' staged entries across lanes (' + counts.distinctStagedEntries + ' distinct)'
|
|
15046
|
+
: (counts.stagedEntries ? ', ' + counts.stagedEntries + ' staged entries' : '')));
|
|
15047
|
+
if (response.envelopeScope === 'all-data-lanes') {
|
|
15048
|
+
console.log('Note: test runs and corpus results are narrowed to the ' + response.dataMode +
|
|
15049
|
+
' lane; envelopes are listed across BOTH lanes (stage/sync evidence is lane-independent).');
|
|
15050
|
+
}
|
|
14813
15051
|
|
|
14814
15052
|
const smells = sortedActivitySmells(response.smells);
|
|
14815
15053
|
console.log('');
|
|
@@ -14819,6 +15057,18 @@ function printActivityInspectSummary(response) {
|
|
|
14819
15057
|
console.log('Top smells (' + smells.length + '):');
|
|
14820
15058
|
smells.slice(0, 20).forEach((smell) => {
|
|
14821
15059
|
console.log(' [' + (smell.severity || 'info') + '] ' + (smell.type || 'signal') + ': ' + smell.summary);
|
|
15060
|
+
// The numbers were in the JSON and not on the line, so twenty signals read as three sentences repeated.
|
|
15061
|
+
const facts = [
|
|
15062
|
+
smell.packetCount != null ? smell.packetCount + ' packet(s)' : null,
|
|
15063
|
+
smell.currentFailureCount != null ? smell.currentFailureCount + ' current failure(s)' : null,
|
|
15064
|
+
smell.requiredCount != null ? smell.requiredCount + ' requirement(s)' : null,
|
|
15065
|
+
smell.openCount != null ? smell.openCount + ' open' : null,
|
|
15066
|
+
smell.recentRuns != null ? smell.recentRuns + ' recent run(s)' : null,
|
|
15067
|
+
smell.failedRuns != null ? smell.failedRuns + ' failed' : null,
|
|
15068
|
+
smell.stagedCount != null ? smell.stagedCount + ' staged' : null,
|
|
15069
|
+
Array.isArray(smell.workspaces) ? smell.workspaces.join(', ') : null
|
|
15070
|
+
].filter(Boolean);
|
|
15071
|
+
if (facts.length) console.log(' ' + facts.join(' · '));
|
|
14822
15072
|
const pivots = [
|
|
14823
15073
|
smell.accountId ? 'account ' + smell.accountId : null,
|
|
14824
15074
|
smell.laneId ? 'lane ' + smell.laneId : null,
|
|
@@ -14831,12 +15081,15 @@ function printActivityInspectSummary(response) {
|
|
|
14831
15081
|
if (pivots.length) console.log(' ' + pivots.join(' · '));
|
|
14832
15082
|
});
|
|
14833
15083
|
if (smells.length > 20) console.log(' ...' + (smells.length - 20) + ' more; rerun with --json');
|
|
14834
|
-
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
15084
|
+
}
|
|
15085
|
+
const actions = buildActivityNextActions(smells);
|
|
15086
|
+
if (actions.length) {
|
|
15087
|
+
console.log('');
|
|
15088
|
+
console.log('Next actions:');
|
|
15089
|
+
actions.forEach((action) => {
|
|
15090
|
+
console.log(' - ' + action.why);
|
|
15091
|
+
if (action.command) console.log(' ' + action.command);
|
|
15092
|
+
});
|
|
14840
15093
|
}
|
|
14841
15094
|
|
|
14842
15095
|
// "2 agent(s)" with no names is the shape of the question, not the answer: an agent asking who else is in
|
|
@@ -14882,8 +15135,14 @@ function printActivityInspectSummary(response) {
|
|
|
14882
15135
|
console.log('');
|
|
14883
15136
|
console.log('Recent verification envelopes:');
|
|
14884
15137
|
envelopes.slice(0, 8).forEach((env) => {
|
|
15138
|
+
const world = [env.branchName || null, env.workspace ? 'ws:' + env.workspace : null, env.dataMode || null]
|
|
15139
|
+
.filter(Boolean).join('/');
|
|
14885
15140
|
console.log(' - ' + (env.status || 'unknown') + ' · ' + (env.packetCount || 0) + ' packet(s) · ' +
|
|
15141
|
+
(world ? '[' + world + '] · ' : '') +
|
|
14886
15142
|
(env.summary || env.envelopeId) + ' · ' + formatTime(env.updatedAtMs || env.lastPacketAtMs || env.createdAt));
|
|
15143
|
+
if (env.noRequiredEvidence) {
|
|
15144
|
+
console.log(' evidence log — no verdict requested; add a claim only if someone needs one: remits-cli verify claim <id> --text "..." --envelope ' + env.envelopeId);
|
|
15145
|
+
}
|
|
14887
15146
|
if (env.currentFailureCount) console.log(' current failures: ' + env.currentFailureCount);
|
|
14888
15147
|
});
|
|
14889
15148
|
}
|
|
@@ -14946,6 +15205,62 @@ function listWorkstreamIndexes(cwd) {
|
|
|
14946
15205
|
.sort((a, b) => String(b.updatedAt || '').localeCompare(String(a.updatedAt || '')));
|
|
14947
15206
|
}
|
|
14948
15207
|
|
|
15208
|
+
async function evidenceCommand(flags) {
|
|
15209
|
+
const cwd = process.cwd();
|
|
15210
|
+
ensureLocalState(cwd);
|
|
15211
|
+
const limit = Math.max(1, Math.min(parseInt(flags.limit || flags.max || '40', 10) || 40, 500));
|
|
15212
|
+
const entries = readEvidenceTrail(cwd, limit);
|
|
15213
|
+
if (flagEnabled(flags.json)) {
|
|
15214
|
+
console.log(JSON.stringify({ success: true, actor: resolveLocalActor().id, count: entries.length, entries }, null, 2));
|
|
15215
|
+
return entries;
|
|
15216
|
+
}
|
|
15217
|
+
const paths = localStatePaths(cwd);
|
|
15218
|
+
console.log('Evidence trail for actor ' + paths.actor.id + ' (' + paths.evidenceFile + ')');
|
|
15219
|
+
if (!entries.length) {
|
|
15220
|
+
console.log('Nothing recorded yet. Every stage, test, token, tool and sync appends one world-stamped line here,');
|
|
15221
|
+
console.log('with no envelope and nothing to start.');
|
|
15222
|
+
return entries;
|
|
15223
|
+
}
|
|
15224
|
+
// Grouped by WORLD, because "what have I proven" is only answerable per world. An agent that ran the same
|
|
15225
|
+
// suite in two lanes has two different facts, and a flat list hides exactly that.
|
|
15226
|
+
const groups = new Map();
|
|
15227
|
+
entries.forEach((entry) => {
|
|
15228
|
+
const key = describeEvidenceWorld(entry.world);
|
|
15229
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
15230
|
+
groups.get(key).push(entry);
|
|
15231
|
+
});
|
|
15232
|
+
groups.forEach((rows, world) => {
|
|
15233
|
+
console.log('');
|
|
15234
|
+
console.log(world);
|
|
15235
|
+
const byClaim = new Map();
|
|
15236
|
+
rows.forEach((row) => {
|
|
15237
|
+
const key = (row.type || 'unknown') + '|' + (row.claim || row.type || 'evidence') + '|' + evidenceOutcome(row);
|
|
15238
|
+
if (!byClaim.has(key)) byClaim.set(key, { row, count: 0 });
|
|
15239
|
+
const bucket = byClaim.get(key);
|
|
15240
|
+
bucket.count += 1;
|
|
15241
|
+
bucket.row = row;
|
|
15242
|
+
});
|
|
15243
|
+
Array.from(byClaim.values())
|
|
15244
|
+
.sort((left, right) => right.count - left.count)
|
|
15245
|
+
.slice(0, 15)
|
|
15246
|
+
.forEach((bucket) => {
|
|
15247
|
+
const row = bucket.row;
|
|
15248
|
+
const layer = row.world && row.world.sourceLayer ? ' source ' + row.world.sourceLayer : '';
|
|
15249
|
+
console.log(' ' + (bucket.count > 1 ? bucket.count + ' x ' : '') +
|
|
15250
|
+
evidenceOutcomeLabel(row) + (row.type || 'unknown') + ': ' + (row.claim || '(no claim)') +
|
|
15251
|
+
' ' + formatTime(row.ts) + layer +
|
|
15252
|
+
(Array.isArray(row.claims) && row.claims.length ? ' [claims ' + row.claims.join(', ') + ']' : '') +
|
|
15253
|
+
(row.envelopeId ? ' [envelope ' + row.envelopeId.slice(0, 8) + ']' : ''));
|
|
15254
|
+
});
|
|
15255
|
+
if (byClaim.size > 15) console.log(' ...' + (byClaim.size - 15) + ' more distinct entries; --json for all');
|
|
15256
|
+
});
|
|
15257
|
+
console.log('');
|
|
15258
|
+
console.log(entries.length + ' entry(s) shown. This is a log, not a verdict: nothing here is outstanding.');
|
|
15259
|
+
console.log('If someone needs a checkable verdict, start an envelope and name what must be true:');
|
|
15260
|
+
console.log(' remits-cli verify start --summary "..." && remits-cli verify claim <id> --text "..."');
|
|
15261
|
+
return entries;
|
|
15262
|
+
}
|
|
15263
|
+
|
|
14949
15264
|
async function workstreamCommand(flags, subcommand) {
|
|
14950
15265
|
const cwd = process.cwd();
|
|
14951
15266
|
ensureLocalState(cwd);
|
|
@@ -16021,6 +16336,9 @@ function printVerifyHelp() {
|
|
|
16021
16336
|
console.log(' remits-cli verify use <envelopeId>');
|
|
16022
16337
|
console.log(' remits-cli verify current');
|
|
16023
16338
|
console.log(' remits-cli verify clear [--all]');
|
|
16339
|
+
console.log(' remits-cli verify claim <id> --text "what must be true" [--test "<suite>"] [--packet-type TYPE]');
|
|
16340
|
+
console.log(' # declares a contract in ONE command when someone needs a verdict; no-contract envelopes are evidence logs');
|
|
16341
|
+
console.log(' # prove it by adding --claim <id> to any verify test/token/tool/stage/attach command');
|
|
16024
16342
|
console.log(' remits-cli verify show [--envelope ID] [--summary|--compact] [--json]');
|
|
16025
16343
|
console.log(' remits-cli verify status [--envelope ID]');
|
|
16026
16344
|
console.log(' remits-cli verify report [--envelope ID]');
|
|
@@ -16142,8 +16460,9 @@ async function main() {
|
|
|
16142
16460
|
console.log(' remits-cli tool --name <toolName> [--base-url URL] [--account-id ID] [--as-account ID] [--target-account ID] [--branch BRANCH] [--input \"{...}\"|--input-file file.json] [--data-mode test|prod] [--scope self|children|hierarchy] [--account-ids 1,2,3] [--variant-branch NAME|none] [--timeout-ms 60000] [--async true --wait true]');
|
|
16143
16461
|
console.log(' remits-cli tool status --call-id <callId> [--base-url URL] [--account-id ID] [--data-mode test|prod]');
|
|
16144
16462
|
console.log(' remits-cli workspace [show|use <name>|use --auto|clear] # isolate staging when several agents share a repo');
|
|
16145
|
-
console.log(' remits-cli
|
|
16146
|
-
|
|
16463
|
+
console.log(' remits-cli evidence [--limit N] [--json] # what you have run and in which world (always recorded)');
|
|
16464
|
+
console.log(' remits-cli verify start --summary "..." [--manifest file.json] # OPTIONAL: ask for a checkable verdict');
|
|
16465
|
+
console.log(' remits-cli verify [current|list|use|clear|show|status|report|claim|attach|abandon|supersede|test|token|stage|sync|tool]');
|
|
16147
16466
|
console.log(' remits-cli components stage [--workset|--changed-only] [--base-url URL] [--account-id ID] [--branch BRANCH] [--workspace NAME] [--data-mode test|prod] [--json|--verbose]');
|
|
16148
16467
|
console.log(' remits-cli components status [--base-url URL] [--account-id ID] [--branch BRANCH] [--workspace NAME] [--component-type TYPE --component-id ID] [--json|--verbose]');
|
|
16149
16468
|
console.log(' remits-cli components lanes [--base-url URL] [--account-id ID] [--json]');
|
|
@@ -16383,6 +16702,22 @@ async function main() {
|
|
|
16383
16702
|
throw new Error('Unknown activity subcommand: ' + subcommand);
|
|
16384
16703
|
}
|
|
16385
16704
|
|
|
16705
|
+
if (command === 'evidence') {
|
|
16706
|
+
if (wantsHelp) {
|
|
16707
|
+
console.log('Usage: remits-cli evidence [--limit N] [--json]');
|
|
16708
|
+
console.log('');
|
|
16709
|
+
console.log('What you have actually run, and in which world. Every stage, test, token, tool and sync');
|
|
16710
|
+
console.log('appends one world-stamped line automatically - there is nothing to start and nothing to');
|
|
16711
|
+
console.log('satisfy. Grouped by world, because the same suite run in two lanes is two different facts.');
|
|
16712
|
+
console.log('');
|
|
16713
|
+
console.log('This is per-actor, so agents sharing a checkout never read each other\'s trail.');
|
|
16714
|
+
console.log('Use `remits-cli verify` only when someone needs a checkable VERDICT on top of this.');
|
|
16715
|
+
return;
|
|
16716
|
+
}
|
|
16717
|
+
await evidenceCommand(args);
|
|
16718
|
+
return;
|
|
16719
|
+
}
|
|
16720
|
+
|
|
16386
16721
|
if (command === 'workstream') {
|
|
16387
16722
|
if (wantsHelp) {
|
|
16388
16723
|
console.log('Usage: remits-cli workstream status [--workstream ID|--workspace NAME] [--json]');
|
package/package.json
CHANGED
|
@@ -162,11 +162,18 @@ reference named after it.
|
|
|
162
162
|
component (preferred, because it becomes regression protection) or a browser flow through
|
|
163
163
|
`remits-cli token`. "Just do it" and "that's fine, commit it" are not evidence. If you genuinely
|
|
164
164
|
cannot verify, say what you would need and ask. (`development-loop.md`)
|
|
165
|
-
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
- **`remits-cli evidence` answers "what have I actually run, and in which world?"** Every stage, test,
|
|
166
|
+
token, tool and sync appends one world-stamped line automatically, per actor. Nothing to start,
|
|
167
|
+
nothing to satisfy. Read it before you re-run something, and quote it when you report what you
|
|
168
|
+
proved. (`development-loop.md`)
|
|
169
|
+
- **Verification envelopes are OPTIONAL and exist for one job: a verdict someone else will rely on.**
|
|
170
|
+
Start one when a ticket, a human, or a handoff needs a checkable "these specific things are true" —
|
|
171
|
+
not as a routine step before editing. `remits-cli verify start --summary "..."` then
|
|
172
|
+
`remits-cli verify claim <id> --text "..." [--test "<suite>"]` names what must be true; add
|
|
173
|
+
`--claim <id>` to the command that proves it; `remits-cli verify report` gives the verdict. An
|
|
174
|
+
envelope with no claims is simply an evidence log, which is a complete state — not something to
|
|
175
|
+
chase. If you find yourself opening an envelope to answer a question about your own work, use
|
|
176
|
+
`remits-cli evidence` instead. (`development-loop.md`, `component-resolution.md`)
|
|
170
177
|
- **Read the component's `.meta.yml` before changing behavior.** Sidecar descriptions can be dated
|
|
171
178
|
decision records. Before changing a displayed value, helper, calculation, schema field, or prompt
|
|
172
179
|
contract, check the sidecar and either preserve its decision or explicitly supersede it.
|
|
@@ -209,8 +216,9 @@ remits-cli tools # which tools this account actually has (tools
|
|
|
209
216
|
```
|
|
210
217
|
|
|
211
218
|
plus the repo's `account-info.json` → `resolution` block for the account's shape.
|
|
212
|
-
For a workflow-shaped request,
|
|
213
|
-
|
|
219
|
+
For a workflow-shaped request, rely on the automatic `remits-cli evidence` trail unless someone else needs
|
|
220
|
+
a checkable verdict. Only then start `remits-cli verify start --summary "..."`, declare claims, and keep
|
|
221
|
+
that envelope active through stage/test/token/sync.
|
|
214
222
|
|
|
215
223
|
If any command returns 401, run `remits-cli auth` (with the same `--base-url` if you were targeting a
|
|
216
224
|
non-default host).
|
|
@@ -344,10 +344,24 @@ shown is the latest run's, with the distinct worlds listed beneath it.
|
|
|
344
344
|
|
|
345
345
|
### Verification envelopes
|
|
346
346
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
347
|
+
**First, the thing you probably want instead.** `remits-cli evidence` prints what you have actually run
|
|
348
|
+
and in which world, grouped by world, with no envelope and nothing to start:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
remits-cli evidence # this actor's trail
|
|
352
|
+
remits-cli evidence --json # structured, for your final report
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Every stage, test, token, tool and sync appends to it automatically. Use it for "what have I already
|
|
356
|
+
run?", "did that execute in the prod lane?" and "what do I put in my final message?".
|
|
357
|
+
|
|
358
|
+
**Verification envelopes are optional, and exist for a verdict someone ELSE will rely on** — a support
|
|
359
|
+
ticket, a human who asked you to prove specific things, a handoff another agent will act on. They are not
|
|
360
|
+
a routine step before editing. An envelope you started for your own benefit is nearly always
|
|
361
|
+
`remits-cli evidence` in disguise, and it costs you turns that prove nothing.
|
|
362
|
+
|
|
363
|
+
When a verdict is genuinely wanted, start it after you know the target
|
|
364
|
+
account/branch/workspace/data-mode tuple:
|
|
351
365
|
|
|
352
366
|
```bash
|
|
353
367
|
remits-cli workspace use --auto
|
|
@@ -355,6 +369,35 @@ remits-cli components status
|
|
|
355
369
|
remits-cli verify start --summary "Hosted upload updates an existing profile" --manifest acceptance.json
|
|
356
370
|
```
|
|
357
371
|
|
|
372
|
+
**Name what must be true, or there is no verdict to reach.** An envelope with no `claims` and no
|
|
373
|
+
`requiredEvidence` reports `evidence_only` — a world-stamped log. That is a complete, final state, not a
|
|
374
|
+
partial one, and nothing about it is outstanding. When you DO want a verdict, a manifest file is one way to
|
|
375
|
+
declare the contract; `verify claim` is the one-command way, and it works on a live envelope:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
remits-cli verify claim market-filter --text "US market scoring excludes AU and GB statements"
|
|
379
|
+
remits-cli verify claim pilot-green --text "the pilot suite passes" --test "Acquirer Pilot"
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Prove a claim by naming it on the command that already proves it. `--claim <id>` is stamped onto the
|
|
383
|
+
evidence packet every command sends, so it works on `verify test`, `token`, `tool`, `stage`, `sync` and
|
|
384
|
+
`attach` alike, and takes a comma-separated list:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
remits-cli verify test --test "Acquirer Pilot" --claim pilot-green
|
|
388
|
+
remits-cli verify tool --name mcp_run_action --as-account 36 --claim market-filter
|
|
389
|
+
remits-cli verify attach --claim market-filter --note "AU statements excluded and counted"
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
A claim with no shape is satisfied by any successful packet tagged with its id. A claim that names a
|
|
393
|
+
`--test` suite (or `--packet-type`) must be proven by that shape. Re-declaring an id replaces it, so
|
|
394
|
+
tightening a claim is also one command.
|
|
395
|
+
|
|
396
|
+
**When an envelope with a contract will not close, read the report — do not start another one.** Several
|
|
397
|
+
open envelopes for the same goal, or workspaces named `...-r7`/`-r8`/`-r9`, is the loop signature, and
|
|
398
|
+
`activity inspect` reports both as smells. Close what you are not finishing: `verify supersede --envelope
|
|
399
|
+
<old> --superseded-by <new>` or `verify abandon --envelope <old> --reason "false start"`.
|
|
400
|
+
|
|
358
401
|
An active envelope is stored per command world (`baseUrl + accountId + git branch + workspace`)
|
|
359
402
|
inside the active local actor's mirror; **data mode is deliberately not part of the active pointer key**:
|
|
360
403
|
`./.remits-cli/actors/<local-agent>/verification/active-contexts.json`. The legacy flat
|
|
@@ -367,7 +410,7 @@ history:
|
|
|
367
410
|
|
|
368
411
|
```bash
|
|
369
412
|
remits-cli verify stage --workset
|
|
370
|
-
remits-cli verify test --test "Adyen Import Recovery" --names "browser upload recovery"
|
|
413
|
+
remits-cli verify test --test "Adyen Import Recovery" --names "browser upload recovery" --claim recovery
|
|
371
414
|
remits-cli verify token --path /page/pricing-config --as-account 21 --data-mode test
|
|
372
415
|
remits-cli verify sync --safe
|
|
373
416
|
remits-cli verify report
|
|
@@ -435,10 +478,10 @@ proof noun: `passed` for a Test case, `measured` for corpus comparisons, `synced
|
|
|
435
478
|
|
|
436
479
|
Final claims should come from `remits-cli verify report`. Treat `Verified` as the acceptance boundary.
|
|
437
480
|
`Additional evidence` is useful handoff context, but it does not satisfy a missing required packet unless
|
|
438
|
-
the report lists it under `Verified`. If the report says `
|
|
439
|
-
say that plainly instead of widening the claim. In
|
|
440
|
-
|
|
441
|
-
action.
|
|
481
|
+
the report lists it under `Verified`. If the report says `evidence_only`, no verdict was requested; if it
|
|
482
|
+
says `partially_verified`, stale, or missing evidence, say that plainly instead of widening the claim. In
|
|
483
|
+
particular, staged proof is not committed variant/trunk proof, a token is not browser proof, and a direct
|
|
484
|
+
DOM or Alpine state mutation is not the same as a user action.
|
|
442
485
|
|
|
443
486
|
Evidence from the wrong world is excluded before it can satisfy a requirement. When the manifest declares
|
|
444
487
|
fields such as `repoAccountId`, `gitBranch`, `componentBranch`, `workspace`, or `dataMode`, the report names
|
|
@@ -201,9 +201,39 @@ runs resolve and what a sync writes. If `account-info.json` carries a `component
|
|
|
201
201
|
variants of these components exist: editing an origin component will drift them, so check
|
|
202
202
|
`remits-cli components branches` before changing shared code. See `branch-variants.md`.
|
|
203
203
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
**You do not need to start anything to have a record.** Every stage, test, token, tool and sync appends a
|
|
205
|
+
world-stamped line to your actor's evidence trail automatically. Read it with:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
remits-cli evidence
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
That is the right tool for "what have I already run?", "did that test actually execute in the prod lane?",
|
|
212
|
+
and "what should I put in my final message?". It is per-actor, so agents sharing a checkout never read each
|
|
213
|
+
other's trail.
|
|
214
|
+
|
|
215
|
+
**Start a verification envelope only when someone else needs a verdict** — a support ticket, a human who
|
|
216
|
+
asked you to prove specific things, or a handoff another agent will act on. It is not a routine step before
|
|
217
|
+
editing, and an envelope you open for your own benefit is almost always `remits-cli evidence` in disguise.
|
|
218
|
+
|
|
219
|
+
When you do want a verdict, name what must be true. One command, no manifest file:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
remits-cli verify start --summary "Hosted upload updates an existing profile"
|
|
223
|
+
remits-cli verify claim fees-balance --text "statement fee totals reconcile to source within five cents"
|
|
224
|
+
remits-cli verify claim pilot-green --text "the pilot suite passes" --test "Acquirer Pilot"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Prove a claim by naming it on the command that already proves it — `--claim <id>` works on `verify
|
|
228
|
+
test`, `token`, `tool`, `stage`, `sync` and `attach` alike:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
remits-cli verify test --test "Acquirer Pilot" --claim pilot-green
|
|
232
|
+
remits-cli verify attach --claim fees-balance --note "34025 reconciles at 0.02 variance"
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
An envelope with no claims reports `evidence_only`. That is a complete, final state — a log, not a
|
|
236
|
+
half-finished exam. Nothing about it is outstanding.
|
|
207
237
|
|
|
208
238
|
#### Step 2: Make the Change
|
|
209
239
|
Edit component files under `components/`. This is local file editing — the platform doesn't know about your changes yet.
|