snipara-companion 2.0.4 → 2.0.6

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/README.md CHANGED
@@ -724,6 +724,12 @@ snipara-companion run \
724
724
  package-surface review, verification plan, and final Judgment Card. Review-only
725
725
  guard findings can be acknowledged with the printed guard action card command;
726
726
  blocking conflicts still make the release judgment non-proceedable.
727
+ When a served judgment id is available, add `--served-judgment-id` so `run` can
728
+ write first-party Advisor Influence receipts for recommendations that visibly
729
+ change the plan. The receipt payload includes stable skip/record counts,
730
+ bounded automation metadata, and observed verification evidence from guard,
731
+ package review, and policy-gate results without treating those checks as
732
+ outcome proof.
727
733
 
728
734
  For the full Project Intelligence and Continuity Layer roadmap, scaffold the
729
735
  built-in managed workflow plan:
package/dist/index.d.ts CHANGED
@@ -565,7 +565,21 @@ interface RecordAdvisorInfluenceReceiptInput {
565
565
  behaviorChange: string;
566
566
  verificationExecuted: string[];
567
567
  outcomeLinkStatus?: AdvisorInfluenceOutcomeLinkStatus;
568
- metadata?: Record<string, unknown>;
568
+ metadata?: AdvisorInfluenceReceiptMetadataInput;
569
+ }
570
+ interface AdvisorInfluenceReceiptMetadataInput extends Record<string, unknown> {
571
+ source?: string;
572
+ firstParty?: boolean;
573
+ planBefore?: string | null;
574
+ planAfter?: string | null;
575
+ changedBecauseOfRecommendation?: boolean | null;
576
+ filesAffected?: string[];
577
+ toolActions?: string[];
578
+ humanOverride?: string | null;
579
+ task?: string | null;
580
+ branch?: string | null;
581
+ runId?: string | null;
582
+ generatedAt?: string | null;
569
583
  }
570
584
  interface RecordAdvisorInfluenceReceiptResult {
571
585
  project: {
@@ -2129,17 +2143,24 @@ interface ProjectRunPackageReview {
2129
2143
  }
2130
2144
  interface ProjectRunAdvisorReceiptWrite {
2131
2145
  advisorRecommendationId: string;
2132
- status: "recorded" | "error";
2146
+ status: "recorded" | "skipped" | "error";
2147
+ agentDecision?: AdvisorInfluenceAgentDecision;
2148
+ changedBecauseOfRecommendation?: boolean;
2133
2149
  result?: RecordAdvisorInfluenceReceiptResult;
2150
+ reason?: ProjectRunAdvisorReceiptSkipReason;
2134
2151
  error?: string;
2135
2152
  }
2153
+ type ProjectRunAdvisorReceiptSkipReason = "explicitly_skipped" | "no_advisor_recommendations" | "missing_served_judgment_id" | "no_plan_adaptation" | "write_limit_exceeded";
2136
2154
  interface ProjectRunAdvisorReceiptCapture {
2137
2155
  status: "skipped" | "recorded" | "partial" | "error";
2138
2156
  servedJudgmentId?: string;
2157
+ totalRecommendationCount: number;
2158
+ eligibleCount: number;
2139
2159
  attemptedCount: number;
2140
2160
  recordedCount: number;
2161
+ skippedCount: number;
2141
2162
  writes: ProjectRunAdvisorReceiptWrite[];
2142
- reason?: string;
2163
+ reason?: ProjectRunAdvisorReceiptSkipReason;
2143
2164
  }
2144
2165
  interface ProjectIntelligenceRunResult {
2145
2166
  version: "project-intelligence.production-run.v1";
package/dist/index.js CHANGED
@@ -11945,6 +11945,7 @@ function formatPolicyGateDecision(gateDecision) {
11945
11945
  // src/commands/run.ts
11946
11946
  var GUARD_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
11947
11947
  var RAW_OUTPUT_PREVIEW_BYTES = 64e3;
11948
+ var ADVISOR_RECEIPT_WRITE_LIMIT = 6;
11948
11949
  function normalizeStringList2(values) {
11949
11950
  return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))];
11950
11951
  }
@@ -12036,6 +12037,21 @@ function advisorReceiptDecision(recommendation, judgmentCard) {
12036
12037
  }
12037
12038
  return "modified";
12038
12039
  }
12040
+ function advisorReceiptChangedBecauseOfRecommendation(args) {
12041
+ if (args.recommendation.severity === "block" && args.judgmentCard.canProceed === "block") {
12042
+ return true;
12043
+ }
12044
+ if (args.recommendation.severity === "risk") {
12045
+ return true;
12046
+ }
12047
+ if (args.recommendation.expectedBehaviorChange?.trim()) {
12048
+ return true;
12049
+ }
12050
+ if (args.recommendation.recommendedVerification.length > 0) {
12051
+ return true;
12052
+ }
12053
+ return args.judgmentCard.requiredActions.length > 0;
12054
+ }
12039
12055
  function advisorReceiptBehaviorChange(recommendation, judgmentCard) {
12040
12056
  const verification = recommendation.recommendedVerification.slice(0, 3).join("; ");
12041
12057
  const mode = recommendation.severity === "block" || recommendation.severity === "risk" ? "required action" : "advisory action";
@@ -12046,73 +12062,243 @@ function advisorReceiptBehaviorChange(recommendation, judgmentCard) {
12046
12062
  `Judgment state after adaptation: ${judgmentCard.state}.`
12047
12063
  ].filter(Boolean).join(" ");
12048
12064
  }
12065
+ function advisorReceiptPlanBefore(options) {
12066
+ return options.task ?? options.diffSummary ?? (options.changedFiles && options.changedFiles.length > 0 ? `Work on ${options.changedFiles.slice(0, 8).join(", ")}` : null);
12067
+ }
12068
+ function advisorReceiptPlanAfter(args) {
12069
+ const requiredActions = args.judgmentCard.requiredActions.slice(0, 5).map((action) => action.command ?? action.title).filter(Boolean);
12070
+ return [
12071
+ args.behaviorChange,
12072
+ requiredActions.length > 0 ? `Visible plan now includes required action(s): ${requiredActions.join("; ")}.` : null,
12073
+ args.recommendation.recommendedVerification.length > 0 ? `Recommended verification stays open: ${args.recommendation.recommendedVerification.slice(0, 5).join("; ")}.` : null
12074
+ ].filter(Boolean).join(" ");
12075
+ }
12076
+ function advisorReceiptMetadata(args) {
12077
+ const toolActions = normalizeStringList2([
12078
+ ...args.recommendation.recommendedVerification,
12079
+ ...args.judgmentCard.requiredActions.map((action) => action.command ?? action.title)
12080
+ ]).slice(0, 20);
12081
+ const filesAffected = normalizeStringList2([
12082
+ ...args.brief.changedFiles ?? [],
12083
+ ...args.options.changedFiles ?? []
12084
+ ]).slice(0, 80);
12085
+ return {
12086
+ source: "snipara-companion:run",
12087
+ firstParty: true,
12088
+ runVersion: "project-intelligence.production-run.v1",
12089
+ runId: process.env.SNIPARA_SESSION_ID ?? process.env.CODEX_SESSION_ID ?? null,
12090
+ generatedAt: args.judgmentCard.generatedAt,
12091
+ release: Boolean(args.options.release),
12092
+ task: args.brief.task ?? args.options.task ?? null,
12093
+ branch: args.brief.branch ?? args.options.branch ?? null,
12094
+ filesAffected,
12095
+ changedFiles: filesAffected,
12096
+ planBefore: advisorReceiptPlanBefore(args.options),
12097
+ planAfter: advisorReceiptPlanAfter({
12098
+ recommendation: args.recommendation,
12099
+ behaviorChange: args.behaviorChange,
12100
+ judgmentCard: args.judgmentCard
12101
+ }),
12102
+ changedBecauseOfRecommendation: args.agentDecision !== "ignored",
12103
+ toolActions,
12104
+ humanOverride: null,
12105
+ judgmentState: args.judgmentCard.state,
12106
+ canProceed: args.judgmentCard.canProceed,
12107
+ verificationEvidence: args.verificationEvidence,
12108
+ verificationBackfill: {
12109
+ version: "advisor-receipt-verification-backfill-v1",
12110
+ executedCount: args.verificationEvidence.filter((item) => item.status !== "skipped").length,
12111
+ skippedCount: args.verificationEvidence.filter((item) => item.status === "skipped").length,
12112
+ caveat: "Verification evidence records commands or gates observed by this run; it is not outcome proof."
12113
+ },
12114
+ receiptAutomation: {
12115
+ version: "first-party-advisor-receipt-automation-v1",
12116
+ trigger: "snipara-companion run",
12117
+ selectedRecommendationRank: args.recommendationIndex + 1,
12118
+ totalRecommendations: args.totalRecommendations,
12119
+ writeLimit: ADVISOR_RECEIPT_WRITE_LIMIT,
12120
+ skipReason: null,
12121
+ reason: "served judgment id and plan adaptation were present"
12122
+ }
12123
+ };
12124
+ }
12125
+ function skippedAdvisorReceiptWrite(recommendation, reason, agentDecision, changedBecauseOfRecommendation) {
12126
+ return {
12127
+ advisorRecommendationId: recommendation.id,
12128
+ status: "skipped",
12129
+ ...agentDecision ? { agentDecision } : {},
12130
+ ...changedBecauseOfRecommendation !== void 0 ? { changedBecauseOfRecommendation } : {},
12131
+ reason
12132
+ };
12133
+ }
12134
+ function advisorReceiptCaptureStatus(args) {
12135
+ if (args.eligibleCount === 0) return "skipped";
12136
+ if (args.recordedCount === args.eligibleCount && args.errorCount === 0 && args.skippedCount === 0) {
12137
+ return "recorded";
12138
+ }
12139
+ if (args.recordedCount > 0) return "partial";
12140
+ if (args.errorCount > 0) return "error";
12141
+ return "skipped";
12142
+ }
12143
+ function verificationEvidenceFromRun(args) {
12144
+ const evidence = [];
12145
+ if (args.guard) {
12146
+ evidence.push({
12147
+ source: "collaboration_guard",
12148
+ label: "Collaboration guard",
12149
+ status: args.guard.status === 0 ? "passed" : "failed",
12150
+ command: args.guard.command,
12151
+ exitCode: args.guard.status,
12152
+ detail: args.guard.status === 0 ? "Pre-deploy collaboration guard passed or only review-only warnings were acknowledged." : args.guard.error ?? args.guard.stderr.trim() ?? `Guard exited ${args.guard.status}.`
12153
+ });
12154
+ }
12155
+ if (args.packageReview) {
12156
+ evidence.push({
12157
+ source: "package_review",
12158
+ label: "Package surface review",
12159
+ status: args.packageReview.status === "ok" ? "passed" : args.packageReview.status === "skipped" ? "skipped" : "failed",
12160
+ command: args.packageReview.command,
12161
+ detail: args.packageReview.status === "ok" ? "npm package metadata was read successfully." : args.packageReview.error ?? `Package review ${args.packageReview.status}.`
12162
+ });
12163
+ }
12164
+ if (args.policyGates) {
12165
+ evidence.push({
12166
+ source: "policy_gates",
12167
+ label: "Policy gates",
12168
+ status: args.policyGates.summary.block > 0 ? "failed" : args.policyGates.summary.requiredAction > 0 ? "warning" : "passed",
12169
+ detail: `Strongest policy gate: ${args.policyGates.summary.strongestSeverity}; advisory ${args.policyGates.summary.advisory}, required ${args.policyGates.summary.requiredAction}, block ${args.policyGates.summary.block}.`
12170
+ });
12171
+ }
12172
+ return evidence;
12173
+ }
12174
+ function verificationExecutedFromEvidence(evidence) {
12175
+ return evidence.filter((item) => item.status !== "skipped").map(
12176
+ (item) => item.command ? `${item.label}: ${item.command} (${item.status})` : `${item.label}: ${item.status}`
12177
+ );
12178
+ }
12049
12179
  async function recordFirstPartyAdvisorReceipts(args) {
12180
+ const allRecommendations = args.judgmentCard.advisorRecommendations;
12050
12181
  if (args.options.skipAdvisorReceipts) {
12051
12182
  return {
12052
12183
  status: "skipped",
12184
+ totalRecommendationCount: allRecommendations.length,
12185
+ eligibleCount: 0,
12053
12186
  attemptedCount: 0,
12054
12187
  recordedCount: 0,
12188
+ skippedCount: allRecommendations.length,
12055
12189
  writes: [],
12056
- reason: "advisor receipt capture was explicitly skipped"
12190
+ reason: "explicitly_skipped"
12057
12191
  };
12058
12192
  }
12059
- if (args.judgmentCard.advisorRecommendations.length === 0) {
12060
- return void 0;
12193
+ if (allRecommendations.length === 0) {
12194
+ return {
12195
+ status: "skipped",
12196
+ totalRecommendationCount: 0,
12197
+ eligibleCount: 0,
12198
+ attemptedCount: 0,
12199
+ recordedCount: 0,
12200
+ skippedCount: 0,
12201
+ writes: [],
12202
+ reason: "no_advisor_recommendations"
12203
+ };
12061
12204
  }
12062
12205
  const servedJudgmentId = servedJudgmentIdForRun(args.options, args.brief);
12063
12206
  if (!servedJudgmentId) {
12207
+ const writes2 = allRecommendations.slice(0, ADVISOR_RECEIPT_WRITE_LIMIT).map(
12208
+ (recommendation) => skippedAdvisorReceiptWrite(recommendation, "missing_served_judgment_id")
12209
+ );
12064
12210
  return {
12065
12211
  status: "skipped",
12212
+ totalRecommendationCount: allRecommendations.length,
12213
+ eligibleCount: 0,
12066
12214
  attemptedCount: 0,
12067
12215
  recordedCount: 0,
12068
- writes: [],
12069
- reason: "no served judgment id was available for first-party advisor receipts"
12216
+ skippedCount: writes2.length,
12217
+ writes: writes2,
12218
+ reason: "missing_served_judgment_id"
12070
12219
  };
12071
12220
  }
12072
12221
  const client = createClient(1e4);
12073
- const recommendations = args.judgmentCard.advisorRecommendations.slice(0, 6);
12074
- const writes = await Promise.all(
12075
- recommendations.map(async (recommendation) => {
12076
- try {
12077
- const result = await client.recordAdvisorInfluenceReceipt({
12078
- servedJudgmentId,
12079
- recommendation: advisorReceiptRecommendation(recommendation),
12080
- agentDecision: advisorReceiptDecision(recommendation, args.judgmentCard),
12081
- behaviorChange: advisorReceiptBehaviorChange(recommendation, args.judgmentCard),
12082
- verificationExecuted: [],
12083
- outcomeLinkStatus: "pending",
12084
- metadata: {
12085
- source: "snipara-companion:run",
12086
- firstParty: true,
12087
- runVersion: "project-intelligence.production-run.v1",
12088
- generatedAt: args.judgmentCard.generatedAt,
12089
- release: Boolean(args.options.release),
12090
- branch: args.brief.branch ?? args.options.branch ?? null,
12091
- changedFiles: args.brief.changedFiles,
12092
- judgmentState: args.judgmentCard.state,
12093
- canProceed: args.judgmentCard.canProceed
12222
+ const verificationEvidence = args.verificationEvidence ?? [];
12223
+ const verificationExecuted = verificationExecutedFromEvidence(verificationEvidence);
12224
+ const selectedRecommendations = allRecommendations.slice(0, ADVISOR_RECEIPT_WRITE_LIMIT);
12225
+ const overflowWrites = allRecommendations.slice(ADVISOR_RECEIPT_WRITE_LIMIT).map((recommendation) => skippedAdvisorReceiptWrite(recommendation, "write_limit_exceeded"));
12226
+ const writes = [
12227
+ ...await Promise.all(
12228
+ selectedRecommendations.map(
12229
+ async (recommendation, recommendationIndex) => {
12230
+ const agentDecision = advisorReceiptDecision(recommendation, args.judgmentCard);
12231
+ const changedBecauseOfRecommendation = advisorReceiptChangedBecauseOfRecommendation({
12232
+ recommendation,
12233
+ judgmentCard: args.judgmentCard
12234
+ });
12235
+ if (!changedBecauseOfRecommendation) {
12236
+ return skippedAdvisorReceiptWrite(
12237
+ recommendation,
12238
+ "no_plan_adaptation",
12239
+ agentDecision,
12240
+ false
12241
+ );
12094
12242
  }
12095
- });
12096
- return {
12097
- advisorRecommendationId: recommendation.id,
12098
- status: "recorded",
12099
- result
12100
- };
12101
- } catch (error) {
12102
- return {
12103
- advisorRecommendationId: recommendation.id,
12104
- status: "error",
12105
- error: error instanceof Error ? error.message : String(error)
12106
- };
12107
- }
12108
- })
12109
- );
12243
+ try {
12244
+ const behaviorChange = advisorReceiptBehaviorChange(recommendation, args.judgmentCard);
12245
+ const result = await client.recordAdvisorInfluenceReceipt({
12246
+ servedJudgmentId,
12247
+ recommendation: advisorReceiptRecommendation(recommendation),
12248
+ agentDecision,
12249
+ behaviorChange,
12250
+ verificationExecuted,
12251
+ outcomeLinkStatus: "pending",
12252
+ metadata: advisorReceiptMetadata({
12253
+ options: args.options,
12254
+ brief: args.brief,
12255
+ judgmentCard: args.judgmentCard,
12256
+ recommendation,
12257
+ recommendationIndex,
12258
+ totalRecommendations: allRecommendations.length,
12259
+ verificationEvidence,
12260
+ agentDecision,
12261
+ behaviorChange
12262
+ })
12263
+ });
12264
+ return {
12265
+ advisorRecommendationId: recommendation.id,
12266
+ status: "recorded",
12267
+ agentDecision,
12268
+ changedBecauseOfRecommendation,
12269
+ result
12270
+ };
12271
+ } catch (error) {
12272
+ return {
12273
+ advisorRecommendationId: recommendation.id,
12274
+ status: "error",
12275
+ agentDecision,
12276
+ changedBecauseOfRecommendation,
12277
+ error: error instanceof Error ? error.message : String(error)
12278
+ };
12279
+ }
12280
+ }
12281
+ )
12282
+ ),
12283
+ ...overflowWrites
12284
+ ];
12110
12285
  const recordedCount = writes.filter((write) => write.status === "recorded").length;
12286
+ const skippedCount = writes.filter((write) => write.status === "skipped").length;
12287
+ const errorCount = writes.filter((write) => write.status === "error").length;
12288
+ const eligibleCount = writes.filter((write) => write.status !== "skipped").length;
12111
12289
  return {
12112
- status: recordedCount === writes.length ? "recorded" : recordedCount > 0 ? "partial" : "error",
12290
+ status: advisorReceiptCaptureStatus({
12291
+ eligibleCount,
12292
+ recordedCount,
12293
+ skippedCount,
12294
+ errorCount
12295
+ }),
12113
12296
  servedJudgmentId,
12114
- attemptedCount: writes.length,
12297
+ totalRecommendationCount: allRecommendations.length,
12298
+ eligibleCount,
12299
+ attemptedCount: eligibleCount,
12115
12300
  recordedCount,
12301
+ skippedCount,
12116
12302
  writes
12117
12303
  };
12118
12304
  }
@@ -12231,11 +12417,6 @@ async function buildProjectIntelligenceRun(options) {
12231
12417
  packageReview,
12232
12418
  errors: runErrors
12233
12419
  });
12234
- const advisorReceiptCapture = await recordFirstPartyAdvisorReceipts({
12235
- options,
12236
- brief,
12237
- judgmentCard
12238
- });
12239
12420
  const policyGates = evaluateProjectPolicyGates({
12240
12421
  task: options.task,
12241
12422
  release: options.release,
@@ -12247,6 +12428,17 @@ async function buildProjectIntelligenceRun(options) {
12247
12428
  packageReview,
12248
12429
  judgmentCard
12249
12430
  });
12431
+ const verificationEvidence = verificationEvidenceFromRun({
12432
+ guard,
12433
+ packageReview,
12434
+ policyGates
12435
+ });
12436
+ const advisorReceiptCapture = await recordFirstPartyAdvisorReceipts({
12437
+ options,
12438
+ brief,
12439
+ judgmentCard,
12440
+ verificationEvidence
12441
+ });
12250
12442
  const suggestedCommands = [
12251
12443
  ...brief.suggestedCommands,
12252
12444
  ...policyGates.suggestedCommands,
@@ -12325,8 +12517,16 @@ async function projectIntelligenceRunCommand(options) {
12325
12517
  console.log(
12326
12518
  `Recorded: ${result.advisorReceiptCapture.recordedCount}/${result.advisorReceiptCapture.attemptedCount}`
12327
12519
  );
12520
+ if (result.advisorReceiptCapture.skippedCount > 0) {
12521
+ console.log(`Skipped: ${result.advisorReceiptCapture.skippedCount}`);
12522
+ }
12328
12523
  if (result.advisorReceiptCapture.reason) {
12329
- console.log(result.advisorReceiptCapture.reason);
12524
+ console.log(`Reason: ${result.advisorReceiptCapture.reason}`);
12525
+ }
12526
+ for (const write of result.advisorReceiptCapture.writes.slice(0, 4)) {
12527
+ if (write.status === "skipped" && write.reason) {
12528
+ console.log(`- skipped ${write.advisorRecommendationId}: ${write.reason}`);
12529
+ }
12330
12530
  }
12331
12531
  console.log("");
12332
12532
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snipara-companion",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "Snipara Git-style companion CLI for local workflow continuity, hooks, hosted context, and Mini Snipara OSS workflows",
5
5
  "main": "dist/index.js",
6
6
  "bin": {