snipara-companion 3.0.13 → 3.0.14
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 +7 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +236 -6
- package/docs/FULL_REFERENCE.md +11 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,6 +47,7 @@ These commands are useful without hosted Snipara:
|
|
|
47
47
|
| `code callers` / `imports` / `neighbors` / `shortest-path` | Structural repo questions from local files |
|
|
48
48
|
| `workflow start` / `phase-start` / `phase-commit` / `resume` | Agent continuity that survives compaction |
|
|
49
49
|
| `workflow producer-report` | Local Producer Loop adoption and calibration report |
|
|
50
|
+
| `workflow producer-review` | Mark local Producer Loop samples reviewed or rejected |
|
|
50
51
|
| `context-pack` | Reversible local packs for long logs, diffs, and tool output |
|
|
51
52
|
| `judgment-card`, `verify`, `lead-plan`, `agent-readiness` | Local review artifacts and delegation contracts |
|
|
52
53
|
| `intelligence ledger-export` | Structured redacted ledger JSON for replay and review |
|
|
@@ -64,6 +65,7 @@ npx -y snipara-companion lead-plan --from-plan ./project-health-lead-plan.json -
|
|
|
64
65
|
npx -y snipara-companion lead-plan --from-plan ./project-health-lead-plan.json --json | jq '.engineeringLeadPlan.executionReceipts'
|
|
65
66
|
npx -y snipara-companion workflow phase-commit audit --summary "mapped auth impact"
|
|
66
67
|
npx -y snipara-companion workflow producer-report
|
|
68
|
+
npx -y snipara-companion workflow producer-review --latest --outcome useful --reviewer alice
|
|
67
69
|
npx -y snipara-companion handoff --summary "auth impact mapped" --next "run auth tests"
|
|
68
70
|
```
|
|
69
71
|
|
|
@@ -76,10 +78,14 @@ under `.snipara/producer-loop/`. These are local review evidence backed by the
|
|
|
76
78
|
redacted Coding Intelligence Ledger, not automatic durable memory, worker
|
|
77
79
|
execution, calibrated confidence, or server-side attestation. Use
|
|
78
80
|
`workflow producer-report` to inspect local adoption, reason-code counts, sample
|
|
79
|
-
size, invalid artifacts, and calibration
|
|
81
|
+
size, reviewed/rejected/unreviewed counts, invalid artifacts, and calibration
|
|
82
|
+
caveats before any future hard gate.
|
|
80
83
|
The report also recognizes exported PR Answer Pack decision-capture artifacts
|
|
81
84
|
with producer kind `pr_answer_pack_decision_capture`, so calibration can track
|
|
82
85
|
more than the workflow producer once those artifacts are present locally.
|
|
86
|
+
Use `workflow producer-review --artifact <path|file|artifactId>` or
|
|
87
|
+
`workflow producer-review --latest` after auditing embedded evidence to move a
|
|
88
|
+
sample from `sample_unreviewed` to `sample_reviewed` or `sample_rejected`.
|
|
83
89
|
|
|
84
90
|
## Local First, Hosted When Useful
|
|
85
91
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2795,6 +2795,7 @@ declare const PRODUCER_LOOP_ARTIFACT_VERSION: "snipara.producer_loop_artifact.v0
|
|
|
2795
2795
|
declare const PRODUCER_LOOP_REPORT_VERSION: "snipara.producer_loop_report.v0";
|
|
2796
2796
|
declare const PRODUCER_LOOP_RELATIVE_DIR: string;
|
|
2797
2797
|
type ProducerLoopProducerKind = "workflow_phase_commit" | "workflow_final_commit" | "pr_answer_pack_decision_capture";
|
|
2798
|
+
type ProducerLoopSampleReviewStatus = "sample_unreviewed" | "sample_reviewed" | "sample_rejected";
|
|
2798
2799
|
interface ProducerLoopArtifactWriteResult {
|
|
2799
2800
|
status: "written" | "error";
|
|
2800
2801
|
schemaVersion: typeof PRODUCER_LOOP_ARTIFACT_VERSION;
|
|
@@ -2820,6 +2821,10 @@ interface ProducerLoopArtifactReportSummary {
|
|
|
2820
2821
|
reasonCodes: string[];
|
|
2821
2822
|
files: string[];
|
|
2822
2823
|
calibrationStatus?: string;
|
|
2824
|
+
reviewStatus: ProducerLoopSampleReviewStatus;
|
|
2825
|
+
reviewOutcome?: string;
|
|
2826
|
+
reviewedAt?: string;
|
|
2827
|
+
reviewer?: string;
|
|
2823
2828
|
}
|
|
2824
2829
|
interface ProducerLoopReport {
|
|
2825
2830
|
version: typeof PRODUCER_LOOP_REPORT_VERSION;
|
|
@@ -2847,7 +2852,11 @@ interface ProducerLoopReport {
|
|
|
2847
2852
|
calibration: {
|
|
2848
2853
|
status: "no_samples" | "insufficient_samples" | "reviewable_sample_set";
|
|
2849
2854
|
sampleSize: number;
|
|
2855
|
+
reviewedSampleSize: number;
|
|
2856
|
+
rejectedSampleSize: number;
|
|
2857
|
+
unreviewedSampleSize: number;
|
|
2850
2858
|
minReviewSampleSize: number;
|
|
2859
|
+
reviewOutcomes: Record<string, number>;
|
|
2851
2860
|
hardGateReady: false;
|
|
2852
2861
|
notes: string[];
|
|
2853
2862
|
};
|
package/dist/index.js
CHANGED
|
@@ -14605,6 +14605,16 @@ function countStringOccurrences(values) {
|
|
|
14605
14605
|
function isProducerLoopProducerKind(value) {
|
|
14606
14606
|
return value === "workflow_phase_commit" || value === "workflow_final_commit" || value === "pr_answer_pack_decision_capture";
|
|
14607
14607
|
}
|
|
14608
|
+
function isProducerLoopSampleReviewStatus(value) {
|
|
14609
|
+
return value === "sample_unreviewed" || value === "sample_reviewed" || value === "sample_rejected";
|
|
14610
|
+
}
|
|
14611
|
+
function normalizeProducerLoopSampleReviewStatus(value) {
|
|
14612
|
+
const status = stringValue5(value);
|
|
14613
|
+
return isProducerLoopSampleReviewStatus(status) ? status : "sample_unreviewed";
|
|
14614
|
+
}
|
|
14615
|
+
function isProducerLoopReviewOutcome(value) {
|
|
14616
|
+
return value === "useful" || value === "false_positive" || value === "missing_context" || value === "unsafe" || value === "duplicate" || value === "other";
|
|
14617
|
+
}
|
|
14608
14618
|
function isTaskCommitOutcome(value) {
|
|
14609
14619
|
return ["completed", "partial", "blocked", "abandoned"].includes(value ?? "");
|
|
14610
14620
|
}
|
|
@@ -14630,6 +14640,7 @@ function summarizeProducerLoopArtifactFile(filePath, cwd) {
|
|
|
14630
14640
|
const producer = isRecord7(parsed.producer) ? parsed.producer : void 0;
|
|
14631
14641
|
const ledger = isRecord7(parsed.ledger) ? parsed.ledger : void 0;
|
|
14632
14642
|
const calibration = isRecord7(parsed.calibration) ? parsed.calibration : void 0;
|
|
14643
|
+
const review = isRecord7(parsed.review) ? parsed.review : void 0;
|
|
14633
14644
|
if (!producer) {
|
|
14634
14645
|
throw new Error("artifact is missing producer metadata");
|
|
14635
14646
|
}
|
|
@@ -14643,6 +14654,9 @@ function summarizeProducerLoopArtifactFile(filePath, cwd) {
|
|
|
14643
14654
|
throw new Error("artifact is missing artifactId or generatedAt");
|
|
14644
14655
|
}
|
|
14645
14656
|
const outcome = stringValue5(producer.outcome);
|
|
14657
|
+
const reviewStatus = normalizeProducerLoopSampleReviewStatus(
|
|
14658
|
+
stringValue5(review?.status) ?? stringValue5(calibration?.status)
|
|
14659
|
+
);
|
|
14646
14660
|
return {
|
|
14647
14661
|
artifact: {
|
|
14648
14662
|
artifactId,
|
|
@@ -14657,7 +14671,11 @@ function summarizeProducerLoopArtifactFile(filePath, cwd) {
|
|
|
14657
14671
|
ledgerHash: stringValue5(parsed.ledgerHash),
|
|
14658
14672
|
reasonCodes: uniqueStrings8(stringArrayValue(ledger?.reasonCodes)),
|
|
14659
14673
|
files: uniqueStrings8(stringArrayValue(producer.files)),
|
|
14660
|
-
calibrationStatus: stringValue5(calibration?.status)
|
|
14674
|
+
calibrationStatus: stringValue5(calibration?.status),
|
|
14675
|
+
reviewStatus,
|
|
14676
|
+
reviewOutcome: stringValue5(review?.outcome),
|
|
14677
|
+
reviewedAt: stringValue5(review?.reviewedAt),
|
|
14678
|
+
reviewer: stringValue5(review?.reviewer)
|
|
14661
14679
|
}
|
|
14662
14680
|
};
|
|
14663
14681
|
} catch (error) {
|
|
@@ -14677,11 +14695,11 @@ function listProducerLoopArtifactFiles(cwd) {
|
|
|
14677
14695
|
}
|
|
14678
14696
|
return fs19.readdirSync(dir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => path18.join(dir, fileName)).sort();
|
|
14679
14697
|
}
|
|
14680
|
-
function producerLoopCalibrationStatus(sampleSize, minReviewSampleSize) {
|
|
14698
|
+
function producerLoopCalibrationStatus(sampleSize, reviewedSampleSize, minReviewSampleSize) {
|
|
14681
14699
|
if (sampleSize === 0) {
|
|
14682
14700
|
return "no_samples";
|
|
14683
14701
|
}
|
|
14684
|
-
if (
|
|
14702
|
+
if (reviewedSampleSize < minReviewSampleSize) {
|
|
14685
14703
|
return "insufficient_samples";
|
|
14686
14704
|
}
|
|
14687
14705
|
return "reviewable_sample_set";
|
|
@@ -14709,10 +14727,28 @@ function buildProducerLoopReport(options = {}) {
|
|
|
14709
14727
|
artifacts.flatMap((artifact) => artifact.reasonCodes)
|
|
14710
14728
|
);
|
|
14711
14729
|
const latestArtifact = artifacts[artifacts.length - 1];
|
|
14712
|
-
const
|
|
14730
|
+
const reviewedSampleSize = artifacts.filter(
|
|
14731
|
+
(artifact) => artifact.reviewStatus === "sample_reviewed"
|
|
14732
|
+
).length;
|
|
14733
|
+
const rejectedSampleSize = artifacts.filter(
|
|
14734
|
+
(artifact) => artifact.reviewStatus === "sample_rejected"
|
|
14735
|
+
).length;
|
|
14736
|
+
const unreviewedSampleSize = artifacts.filter(
|
|
14737
|
+
(artifact) => artifact.reviewStatus === "sample_unreviewed"
|
|
14738
|
+
).length;
|
|
14739
|
+
const reviewOutcomes = countStringOccurrences(
|
|
14740
|
+
artifacts.map((artifact) => artifact.reviewOutcome).filter((outcome) => Boolean(outcome))
|
|
14741
|
+
);
|
|
14742
|
+
const calibrationStatus = producerLoopCalibrationStatus(
|
|
14743
|
+
artifacts.length,
|
|
14744
|
+
reviewedSampleSize,
|
|
14745
|
+
minReviewSampleSize
|
|
14746
|
+
);
|
|
14713
14747
|
const recommendedActions = [
|
|
14714
14748
|
artifacts.length === 0 ? "Run a current Producer Loop producer, such as workflow phase-commit/final-commit or PR Answer Pack decision capture, to create samples." : void 0,
|
|
14715
|
-
artifacts.length > 0 &&
|
|
14749
|
+
artifacts.length > 0 && reviewedSampleSize < minReviewSampleSize ? `Review at least ${minReviewSampleSize} local Producer Loop samples before considering any calibration signal.` : void 0,
|
|
14750
|
+
unreviewedSampleSize > 0 ? "Mark local samples with workflow producer-review after checking the embedded evidence." : void 0,
|
|
14751
|
+
rejectedSampleSize > 0 ? "Inspect rejected Producer Loop samples for false positives, missing context, or reason-code drift." : void 0,
|
|
14716
14752
|
invalidArtifacts.length > 0 ? "Inspect invalid Producer Loop artifacts before trusting adoption counts." : void 0,
|
|
14717
14753
|
"Review false positives, missing outcomes, and reason-code drift before any future enforcement."
|
|
14718
14754
|
].filter((item) => Boolean(item));
|
|
@@ -14738,11 +14774,16 @@ function buildProducerLoopReport(options = {}) {
|
|
|
14738
14774
|
calibration: {
|
|
14739
14775
|
status: calibrationStatus,
|
|
14740
14776
|
sampleSize: artifacts.length,
|
|
14777
|
+
reviewedSampleSize,
|
|
14778
|
+
rejectedSampleSize,
|
|
14779
|
+
unreviewedSampleSize,
|
|
14741
14780
|
minReviewSampleSize,
|
|
14781
|
+
reviewOutcomes,
|
|
14742
14782
|
hardGateReady: false,
|
|
14743
14783
|
notes: [
|
|
14744
14784
|
"Producer Loop V0 reports local or exported producer samples only.",
|
|
14745
|
-
"
|
|
14785
|
+
"Only samples marked sample_reviewed count toward calibration review size.",
|
|
14786
|
+
"sample_rejected records operator review but does not count as positive calibration evidence.",
|
|
14746
14787
|
"hardGateReady remains false in V0 even when enough samples exist."
|
|
14747
14788
|
]
|
|
14748
14789
|
},
|
|
@@ -14754,11 +14795,171 @@ function buildProducerLoopReport(options = {}) {
|
|
|
14754
14795
|
]
|
|
14755
14796
|
};
|
|
14756
14797
|
}
|
|
14798
|
+
function resolveProducerLoopReviewTarget(cwd, selector, latest) {
|
|
14799
|
+
const files = listProducerLoopArtifactFiles(cwd);
|
|
14800
|
+
if (files.length === 0) {
|
|
14801
|
+
throw new Error(`No Producer Loop artifacts found under ${PRODUCER_LOOP_RELATIVE_DIR}.`);
|
|
14802
|
+
}
|
|
14803
|
+
const normalizedSelector = selector?.trim();
|
|
14804
|
+
if (!normalizedSelector) {
|
|
14805
|
+
if (!latest) {
|
|
14806
|
+
throw new Error("Pass --artifact <path|file|artifactId> or --latest.");
|
|
14807
|
+
}
|
|
14808
|
+
const summaries = files.map((filePath) => summarizeProducerLoopArtifactFile(filePath, cwd).artifact).filter((entry) => Boolean(entry)).sort(
|
|
14809
|
+
(left, right) => left.generatedAt === right.generatedAt ? left.relativePath.localeCompare(right.relativePath) : left.generatedAt.localeCompare(right.generatedAt)
|
|
14810
|
+
);
|
|
14811
|
+
const latestArtifact = summaries[summaries.length - 1];
|
|
14812
|
+
if (!latestArtifact) {
|
|
14813
|
+
throw new Error("No valid Producer Loop artifacts found to review.");
|
|
14814
|
+
}
|
|
14815
|
+
return latestArtifact.path;
|
|
14816
|
+
}
|
|
14817
|
+
const directCandidates = [
|
|
14818
|
+
path18.resolve(cwd, normalizedSelector),
|
|
14819
|
+
path18.resolve(cwd, PRODUCER_LOOP_RELATIVE_DIR, normalizedSelector)
|
|
14820
|
+
];
|
|
14821
|
+
const directMatch = directCandidates.find((candidate) => fs19.existsSync(candidate));
|
|
14822
|
+
if (directMatch) {
|
|
14823
|
+
return directMatch;
|
|
14824
|
+
}
|
|
14825
|
+
const normalizedPathSelector = normalizedSelector.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
14826
|
+
const matches = files.filter((filePath) => {
|
|
14827
|
+
const relativePath2 = toProjectRelativePath(filePath, cwd).replace(/\\/g, "/");
|
|
14828
|
+
const basename7 = path18.basename(filePath);
|
|
14829
|
+
if (basename7 === normalizedSelector || relativePath2 === normalizedPathSelector || relativePath2.replace(/^\.\//, "") === normalizedPathSelector) {
|
|
14830
|
+
return true;
|
|
14831
|
+
}
|
|
14832
|
+
try {
|
|
14833
|
+
const parsed = JSON.parse(fs19.readFileSync(filePath, "utf-8"));
|
|
14834
|
+
return isRecord7(parsed) && stringValue5(parsed.artifactId) === normalizedSelector;
|
|
14835
|
+
} catch {
|
|
14836
|
+
return false;
|
|
14837
|
+
}
|
|
14838
|
+
});
|
|
14839
|
+
if (matches.length === 0) {
|
|
14840
|
+
throw new Error(`No Producer Loop artifact matched '${normalizedSelector}'.`);
|
|
14841
|
+
}
|
|
14842
|
+
if (matches.length > 1) {
|
|
14843
|
+
throw new Error(
|
|
14844
|
+
`Producer Loop artifact selector '${normalizedSelector}' matched multiple files: ${matches.map((filePath) => toProjectRelativePath(filePath, cwd)).join(", ")}`
|
|
14845
|
+
);
|
|
14846
|
+
}
|
|
14847
|
+
return matches[0];
|
|
14848
|
+
}
|
|
14849
|
+
function readProducerLoopArtifactForReview(filePath) {
|
|
14850
|
+
const parsed = JSON.parse(fs19.readFileSync(filePath, "utf-8"));
|
|
14851
|
+
if (!isRecord7(parsed)) {
|
|
14852
|
+
throw new Error("artifact must be a JSON object");
|
|
14853
|
+
}
|
|
14854
|
+
if (parsed.schemaVersion !== PRODUCER_LOOP_ARTIFACT_VERSION) {
|
|
14855
|
+
throw new Error(
|
|
14856
|
+
`unsupported schemaVersion '${stringValue5(parsed.schemaVersion) ?? "unknown"}'`
|
|
14857
|
+
);
|
|
14858
|
+
}
|
|
14859
|
+
const artifactId = stringValue5(parsed.artifactId);
|
|
14860
|
+
const generatedAt = stringValue5(parsed.generatedAt);
|
|
14861
|
+
if (!artifactId || !generatedAt) {
|
|
14862
|
+
throw new Error("artifact is missing artifactId or generatedAt");
|
|
14863
|
+
}
|
|
14864
|
+
if (!isRecord7(parsed.producer)) {
|
|
14865
|
+
throw new Error("artifact is missing producer metadata");
|
|
14866
|
+
}
|
|
14867
|
+
const producerKind = stringValue5(parsed.producer.kind);
|
|
14868
|
+
if (!isProducerLoopProducerKind(producerKind)) {
|
|
14869
|
+
throw new Error(`unsupported producer kind '${producerKind ?? "unknown"}'`);
|
|
14870
|
+
}
|
|
14871
|
+
return parsed;
|
|
14872
|
+
}
|
|
14873
|
+
function applyProducerLoopArtifactReview(artifact, options) {
|
|
14874
|
+
const reviewNotes = uniqueStrings8(options.notes ?? []);
|
|
14875
|
+
const reviewNote = options.status === "sample_rejected" ? "Sample rejected by local operator review." : "Sample reviewed by local operator.";
|
|
14876
|
+
const existingCalibration = artifact.calibration ?? {
|
|
14877
|
+
status: "sample_unreviewed",
|
|
14878
|
+
sampleSize: 1,
|
|
14879
|
+
hardGateReady: false,
|
|
14880
|
+
notes: []
|
|
14881
|
+
};
|
|
14882
|
+
return {
|
|
14883
|
+
...artifact,
|
|
14884
|
+
calibration: {
|
|
14885
|
+
...existingCalibration,
|
|
14886
|
+
status: options.status,
|
|
14887
|
+
sampleSize: 1,
|
|
14888
|
+
hardGateReady: false,
|
|
14889
|
+
notes: uniqueStrings8([
|
|
14890
|
+
...stringArrayValue(existingCalibration.notes),
|
|
14891
|
+
reviewNote,
|
|
14892
|
+
...reviewNotes.map((note) => `Review note: ${note}`)
|
|
14893
|
+
])
|
|
14894
|
+
},
|
|
14895
|
+
review: {
|
|
14896
|
+
status: options.status,
|
|
14897
|
+
reviewedAt: options.reviewedAt,
|
|
14898
|
+
...options.reviewer ? { reviewer: options.reviewer } : {},
|
|
14899
|
+
...options.outcome ? { outcome: options.outcome } : {},
|
|
14900
|
+
notes: reviewNotes
|
|
14901
|
+
}
|
|
14902
|
+
};
|
|
14903
|
+
}
|
|
14904
|
+
function reviewProducerLoopArtifact(options) {
|
|
14905
|
+
const cwd = path18.resolve(options.cwd ?? process.cwd());
|
|
14906
|
+
const targetPath = resolveProducerLoopReviewTarget(cwd, options.artifact, options.latest);
|
|
14907
|
+
const artifact = readProducerLoopArtifactForReview(targetPath);
|
|
14908
|
+
const rawOutcome = stringValue5(options.outcome);
|
|
14909
|
+
if (rawOutcome && !isProducerLoopReviewOutcome(rawOutcome)) {
|
|
14910
|
+
throw new Error(
|
|
14911
|
+
`Unsupported producer review outcome '${rawOutcome}'. Use useful, false_positive, missing_context, unsafe, duplicate, or other.`
|
|
14912
|
+
);
|
|
14913
|
+
}
|
|
14914
|
+
const outcome = rawOutcome;
|
|
14915
|
+
const status = options.reject ? "sample_rejected" : "sample_reviewed";
|
|
14916
|
+
const reviewer = stringValue5(options.reviewer);
|
|
14917
|
+
const reviewedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14918
|
+
const reviewed = applyProducerLoopArtifactReview(artifact, {
|
|
14919
|
+
status,
|
|
14920
|
+
reviewedAt,
|
|
14921
|
+
...reviewer ? { reviewer } : {},
|
|
14922
|
+
...outcome ? { outcome } : {},
|
|
14923
|
+
notes: options.notes ?? []
|
|
14924
|
+
});
|
|
14925
|
+
fs19.writeFileSync(targetPath, stableJsonStringify(reviewed), "utf-8");
|
|
14926
|
+
const content = fs19.readFileSync(targetPath, "utf-8");
|
|
14927
|
+
return {
|
|
14928
|
+
status: "reviewed",
|
|
14929
|
+
schemaVersion: PRODUCER_LOOP_ARTIFACT_VERSION,
|
|
14930
|
+
artifactId: reviewed.artifactId,
|
|
14931
|
+
path: targetPath,
|
|
14932
|
+
relativePath: toProjectRelativePath(targetPath, cwd),
|
|
14933
|
+
artifactHash: `sha256:${hashContent(content)}`,
|
|
14934
|
+
ledgerHash: reviewed.ledgerHash,
|
|
14935
|
+
review: reviewed.review,
|
|
14936
|
+
calibration: {
|
|
14937
|
+
status: reviewed.calibration.status,
|
|
14938
|
+
hardGateReady: false
|
|
14939
|
+
},
|
|
14940
|
+
caveats: [
|
|
14941
|
+
"Local operator review only; this is not server-side attestation.",
|
|
14942
|
+
"Producer Loop V0 keeps hardGateReady=false after review."
|
|
14943
|
+
]
|
|
14944
|
+
};
|
|
14945
|
+
}
|
|
14946
|
+
function printProducerLoopReviewResult(result) {
|
|
14947
|
+
console.log(import_chalk6.default.bold("Producer Loop Review"));
|
|
14948
|
+
printKeyValue2("Artifact:", result.relativePath);
|
|
14949
|
+
printKeyValue2("Status:", result.review.status);
|
|
14950
|
+
if (result.review.outcome) {
|
|
14951
|
+
printKeyValue2("Outcome:", result.review.outcome);
|
|
14952
|
+
}
|
|
14953
|
+
printKeyValue2("Hard gate ready:", result.calibration.hardGateReady ? "yes" : "no");
|
|
14954
|
+
}
|
|
14757
14955
|
function printProducerLoopReport(report) {
|
|
14758
14956
|
console.log(import_chalk6.default.bold("Producer Loop Report"));
|
|
14759
14957
|
printKeyValue2("Status:", report.adoption.status);
|
|
14760
14958
|
printKeyValue2("Artifacts:", report.adoption.artifactCount);
|
|
14761
14959
|
printKeyValue2("Calibration:", report.calibration.status);
|
|
14960
|
+
printKeyValue2("Reviewed:", report.calibration.reviewedSampleSize);
|
|
14961
|
+
printKeyValue2("Rejected:", report.calibration.rejectedSampleSize);
|
|
14962
|
+
printKeyValue2("Unreviewed:", report.calibration.unreviewedSampleSize);
|
|
14762
14963
|
printKeyValue2("Hard gate ready:", report.calibration.hardGateReady ? "yes" : "no");
|
|
14763
14964
|
if (report.adoption.producerKinds.length > 0) {
|
|
14764
14965
|
printKeyValue2("Producers:", report.adoption.producerKinds.join(", "));
|
|
@@ -14787,6 +14988,21 @@ async function workflowProducerReportCommand(options) {
|
|
|
14787
14988
|
}
|
|
14788
14989
|
printProducerLoopReport(report);
|
|
14789
14990
|
}
|
|
14991
|
+
async function workflowProducerReviewCommand(options) {
|
|
14992
|
+
const result = reviewProducerLoopArtifact({
|
|
14993
|
+
artifact: options.artifact,
|
|
14994
|
+
latest: Boolean(options.latest),
|
|
14995
|
+
reject: Boolean(options.reject),
|
|
14996
|
+
outcome: options.outcome,
|
|
14997
|
+
reviewer: options.reviewer,
|
|
14998
|
+
notes: options.note ?? []
|
|
14999
|
+
});
|
|
15000
|
+
if (options.json) {
|
|
15001
|
+
printJson2(result);
|
|
15002
|
+
return;
|
|
15003
|
+
}
|
|
15004
|
+
printProducerLoopReviewResult(result);
|
|
15005
|
+
}
|
|
14790
15006
|
async function workflowScaffoldCommand(options) {
|
|
14791
15007
|
const preset = parseWorkflowPlanPreset(options.preset);
|
|
14792
15008
|
const scaffold = buildWorkflowPlanScaffold(preset, {
|
|
@@ -29291,6 +29507,20 @@ workflow.command("producer-report").description("Summarize local Producer Loop a
|
|
|
29291
29507
|
json: options.json
|
|
29292
29508
|
});
|
|
29293
29509
|
});
|
|
29510
|
+
workflow.command("producer-review").description("Mark a local Producer Loop artifact as reviewed or rejected").option("--artifact <artifact>", "Artifact path, file name, or artifact id to review").option("--latest", "Review the latest valid Producer Loop artifact").option("--reject", "Mark the sample as rejected instead of reviewed").option(
|
|
29511
|
+
"--outcome <outcome>",
|
|
29512
|
+
"Review outcome: useful, false_positive, missing_context, unsafe, duplicate, or other"
|
|
29513
|
+
).option("--reviewer <reviewer>", "Reviewer name or handle").option("--note <note>", "Review note; repeatable", collectOption, []).option("--json", "Print raw JSON").action(async (options) => {
|
|
29514
|
+
await workflowProducerReviewCommand({
|
|
29515
|
+
artifact: options.artifact,
|
|
29516
|
+
latest: options.latest,
|
|
29517
|
+
reject: options.reject,
|
|
29518
|
+
outcome: options.outcome,
|
|
29519
|
+
reviewer: options.reviewer,
|
|
29520
|
+
note: options.note,
|
|
29521
|
+
json: options.json
|
|
29522
|
+
});
|
|
29523
|
+
});
|
|
29294
29524
|
workflow.command("resume").description(
|
|
29295
29525
|
"Restore managed workflow state plus hosted memory after compaction or resume, including guided Sandbox reattach or rehydrate steps when a runtime checkpoint exists"
|
|
29296
29526
|
).option("--max-critical-tokens <number>", "Durable memory token budget").option("--max-context-tokens <number>", "Short-lived session context token budget").option("--include-session-context", "Include short-lived session carryover").option("--json", "Print raw JSON").action(async (options) => {
|
package/docs/FULL_REFERENCE.md
CHANGED
|
@@ -179,6 +179,7 @@ snipara-companion timeline
|
|
|
179
179
|
snipara-companion workflow phase-commit build --summary "tests green"
|
|
180
180
|
snipara-companion workflow impact-gate
|
|
181
181
|
snipara-companion workflow producer-report
|
|
182
|
+
snipara-companion workflow producer-review --latest --outcome useful --reviewer alice
|
|
182
183
|
snipara-companion workflow run --adaptive-routing-dry-run --route-local-workers "document a scoped change"
|
|
183
184
|
snipara-companion lead-plan --task "ship auth hardening" --changed-files src/auth.ts --proof "pnpm test auth" --acceptance "auth tests pass"
|
|
184
185
|
snipara-companion verify --changed-files src/auth.ts --diff-summary "auth hardening"
|
|
@@ -216,8 +217,12 @@ snipara-companion workflow resume --include-session-context
|
|
|
216
217
|
- `workflow producer-report` scans local Producer Loop artifacts emitted by
|
|
217
218
|
workflow phase/final commits or exported PR Answer Pack decision-capture
|
|
218
219
|
producers, then reports adoption, producer kinds, workflow ids, reason-code
|
|
219
|
-
counts, invalid artifacts, sample size,
|
|
220
|
-
`hardGateReady=false`.
|
|
220
|
+
counts, invalid artifacts, sample size, reviewed/rejected/unreviewed counts,
|
|
221
|
+
and calibration caveats with `hardGateReady=false`.
|
|
222
|
+
- `workflow producer-review` marks one local Producer Loop artifact as
|
|
223
|
+
`sample_reviewed` or `sample_rejected` after operator review. Use
|
|
224
|
+
`--artifact <path|file|artifactId>` for an exact sample or `--latest` for the
|
|
225
|
+
newest valid local artifact.
|
|
221
226
|
- `workflow run --adaptive-routing-dry-run` prints an Adaptive Work Routing
|
|
222
227
|
card. Add `--route-local-workers` when a strong planner should keep deep
|
|
223
228
|
reasoning while a local worker handles scoped execution.
|
|
@@ -243,7 +248,7 @@ The mental model is intentionally close to Git:
|
|
|
243
248
|
| `git show` | `snipara-companion brief` |
|
|
244
249
|
| `git commit` | `snipara-companion workflow phase-commit` |
|
|
245
250
|
| `git diff @{u}..HEAD` | `snipara-companion workflow impact-gate` |
|
|
246
|
-
| review local samples | `snipara-companion workflow producer-
|
|
251
|
+
| review local samples | `snipara-companion workflow producer-review` |
|
|
247
252
|
| `git log` | `snipara-companion timeline` |
|
|
248
253
|
| `git format-patch` | `snipara-companion handoff` |
|
|
249
254
|
| `git checkout` | `snipara-companion workflow resume` |
|
|
@@ -784,6 +789,7 @@ snipara-companion workflow run --mode full --no-runtime-hint --query "implement
|
|
|
784
789
|
snipara-companion workflow run --mode orchestrate --query "map production rollout risks"
|
|
785
790
|
snipara-companion workflow final-commit --summary "Shipped auth hardening and tests" --files src/auth.ts tests/auth.test.ts
|
|
786
791
|
snipara-companion workflow producer-report
|
|
792
|
+
snipara-companion workflow producer-review --artifact producer-abc123 --outcome useful --reviewer alice
|
|
787
793
|
snipara-companion final-commit --summary "Shipped auth hardening and tests" --files src/auth.ts tests/auth.test.ts
|
|
788
794
|
snipara-companion doctor
|
|
789
795
|
snipara-companion doctor --json
|
|
@@ -1072,7 +1078,8 @@ Semantics:
|
|
|
1072
1078
|
- `snipara-companion workflow runtime-checkpoint` = captures a resume-ready Snipara Sandbox checkpoint for one phase using local workflow state plus a hosted automation event when configured
|
|
1073
1079
|
- `snipara-companion workflow phase-commit` = calls hosted `snipara_end_of_task_commit` for that phase, updates local state, and advances the next phase; if the hosted commit times out or hits a transient network failure, local workflow state still advances with an explicit local fallback record
|
|
1074
1080
|
- `snipara-companion workflow phase-commit` and `workflow final-commit` also emit local Producer Loop V0 artifacts under `.snipara/producer-loop/`, backed by the redacted Coding Intelligence Ledger. PR Answer Pack decision capture uses the same schema with producer kind `pr_answer_pack_decision_capture` when the artifact is exported or embedded by the hosted PR pack producer. These artifacts are review evidence only: they do not launch workers, approve durable memory, claim calibrated confidence, or provide server-side attestation.
|
|
1075
|
-
- `snipara-companion workflow producer-report` = scans local Producer Loop artifacts and reports adoption, producer kinds, workflow ids, latest artifact, reason-code counts, invalid artifacts, sample size, and calibration caveats with `hardGateReady=false`
|
|
1081
|
+
- `snipara-companion workflow producer-report` = scans local Producer Loop artifacts and reports adoption, producer kinds, workflow ids, latest artifact, reason-code counts, invalid artifacts, sample size, reviewed/rejected/unreviewed counts, and calibration caveats with `hardGateReady=false`
|
|
1082
|
+
- `snipara-companion workflow producer-review` = marks one local Producer Loop artifact as reviewed or rejected with optional outcome, reviewer, and notes; it does not make `hardGateReady` true
|
|
1076
1083
|
- `snipara-companion workflow phase-commit` and `workflow final-commit` complete matching local Team Sync active work when the workflow is completed. Matching is conservative: exact workflow goal/summary text wins, and file overlap plus meaningful token overlap handles slug-like workflow goals without closing unrelated active work.
|
|
1077
1084
|
- `snipara-companion workflow impact-gate` = local pre-push gate for completed workflow phases in `upstream..HEAD`; it keeps dirty files out of the committed impact analysis and reports phase/file coverage before hosted reindex catches up
|
|
1078
1085
|
- `snipara-companion workflow resume` = reloads local workflow state plus hosted durable memory after compaction or resume, optionally includes short-lived session context with `--include-session-context`, then appends the latest hosted Team Sync handoff/checkpoint context when available; runtime-bound phases also print a Snipara Sandbox reattach or rehydrate plan; rerun `workflow phase-start` before editing again
|