@mytegroupinc/myte-core 0.0.55 → 0.0.56
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 +36 -17
- package/cli.js +366 -63
- package/lib/certification-manifest.js +2 -0
- package/package.json +1 -1
- package/scripts/feedback-live-full-harness.js +145 -0
- package/scripts/mission-live-full-harness.js +10 -9
- package/scripts/project-assistant-live-full-harness.js +208 -174
|
@@ -19,6 +19,7 @@ const LIVE_SCENARIO_MATRIX = [
|
|
|
19
19
|
{ id: "create-independent-prds", kind: "write", mutation: "test_feedback", required: true },
|
|
20
20
|
{ id: "create-three-document-prd", kind: "write", mutation: "test_feedback", required: true },
|
|
21
21
|
{ id: "feedback-sync", kind: "read/local-sync", mutation: "local_temp_only", required: true },
|
|
22
|
+
{ id: "feedback-ticket-batch-lifecycle", kind: "synchronous-governed-write", mutation: "test_feedback_ticket", required: true },
|
|
22
23
|
{ id: "feedback-get-history", kind: "read", mutation: "none", required: true },
|
|
23
24
|
{ id: "feedback-comment", kind: "write", mutation: "test_comment", required: true },
|
|
24
25
|
{ id: "feedback-comment-sync-roundtrip", kind: "read/local-sync", mutation: "local_temp_only", required: true },
|
|
@@ -657,6 +658,150 @@ async function main() {
|
|
|
657
658
|
const collaboratorWriteKey = collaboratorApiKey || ownerApiKey;
|
|
658
659
|
const operationalReviewKey = delegateApiKey || ownerApiKey;
|
|
659
660
|
roleMatrix.collaborator_writes_used = Boolean(collaboratorApiKey);
|
|
661
|
+
|
|
662
|
+
const ticketVersions = runCli([
|
|
663
|
+
"feedback",
|
|
664
|
+
"prd-versions",
|
|
665
|
+
"--feedback-id",
|
|
666
|
+
documentSetFeedbackId,
|
|
667
|
+
"--json",
|
|
668
|
+
...baseArgs,
|
|
669
|
+
], workspace, { apiKey: collaboratorWriteKey }).stdout;
|
|
670
|
+
const ticketVersionId = String(
|
|
671
|
+
ticketVersions.active_prd_version_id
|
|
672
|
+
|| ticketVersions.versions?.[0]?.version_id
|
|
673
|
+
|| ticketVersions.versions?.[0]?._id
|
|
674
|
+
|| "",
|
|
675
|
+
);
|
|
676
|
+
const ticketDocumentId = String(documentSetCreate.documents?.[0]?.document_id || "");
|
|
677
|
+
assert(ticketVersionId && ticketDocumentId, "Ticket certification could not resolve a PRD version/document anchor.");
|
|
678
|
+
const ticketPayloadPath = path.join(workspace, `tickets-${runId}.json`);
|
|
679
|
+
const ticketPayload = {
|
|
680
|
+
items: [
|
|
681
|
+
{
|
|
682
|
+
ticket_key: `${namespace}-api`,
|
|
683
|
+
title: `${namespace} API subticket`,
|
|
684
|
+
summary: "Disposable batch lifecycle certification ticket.",
|
|
685
|
+
severity: "High",
|
|
686
|
+
prd_links: [{ version_id: ticketVersionId, document_id: ticketDocumentId }],
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
ticket_key: `${namespace}-web`,
|
|
690
|
+
title: `${namespace} Web subticket`,
|
|
691
|
+
summary: "Disposable batch lifecycle certification ticket.",
|
|
692
|
+
severity: "Medium",
|
|
693
|
+
prd_links: [{ version_id: ticketVersionId, document_id: ticketDocumentId }],
|
|
694
|
+
},
|
|
695
|
+
],
|
|
696
|
+
};
|
|
697
|
+
fs.writeFileSync(ticketPayloadPath, `${JSON.stringify(ticketPayload, null, 2)}\n`, "utf8");
|
|
698
|
+
const ticketApprovalPath = path.join(workspace, `tickets-${runId}-approval.json`);
|
|
699
|
+
fs.writeFileSync(ticketApprovalPath, `${JSON.stringify({
|
|
700
|
+
command: "myte feedback tickets create",
|
|
701
|
+
reason,
|
|
702
|
+
feedback_id: documentSetFeedbackId,
|
|
703
|
+
batch_count: 2,
|
|
704
|
+
tickets: ticketPayload.items,
|
|
705
|
+
}, null, 2)}\n`, "utf8");
|
|
706
|
+
const ticketValidation = runCli([
|
|
707
|
+
"feedback", "tickets", "create",
|
|
708
|
+
"--feedback-id", documentSetFeedbackId,
|
|
709
|
+
"--file", ticketPayloadPath,
|
|
710
|
+
"--dry-run", "--json", ...baseArgs,
|
|
711
|
+
], workspace, { apiKey: collaboratorWriteKey }).stdout;
|
|
712
|
+
assert(ticketValidation.valid === true && ticketValidation.item_count === 2, "Ticket batch validation did not certify both items.");
|
|
713
|
+
const ticketCreate = runCli([
|
|
714
|
+
"feedback", "tickets", "create",
|
|
715
|
+
"--feedback-id", documentSetFeedbackId,
|
|
716
|
+
"--file", ticketPayloadPath,
|
|
717
|
+
"--confirm-write", "--approval-artifact", ticketApprovalPath,
|
|
718
|
+
"--idempotency-key", `ticket-create-${runId}`,
|
|
719
|
+
"--json", ...baseArgs,
|
|
720
|
+
], workspace, { apiKey: collaboratorWriteKey }).stdout;
|
|
721
|
+
assert(ticketCreate.created_count === 2 && ticketCreate.receipts?.length === 2, "Ticket batch create did not return two receipts.");
|
|
722
|
+
const ticketIds = ticketCreate.receipts.map((receipt) => String(receipt.ticket_id));
|
|
723
|
+
for (const ticketId of ticketIds) {
|
|
724
|
+
recordCertificationArtifact(manifest, {
|
|
725
|
+
kind: "feedback_ticket",
|
|
726
|
+
id: ticketId,
|
|
727
|
+
metadata: { feedback_id: documentSetFeedbackId, cleanup: "retained_with_archived_parent" },
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
if (ticketCreate.batch_id) {
|
|
731
|
+
recordCertificationArtifact(manifest, {
|
|
732
|
+
kind: "ticket_batch",
|
|
733
|
+
id: String(ticketCreate.batch_id),
|
|
734
|
+
metadata: { operation: "create", feedback_id: documentSetFeedbackId },
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
const ticketUpdateApprovalPath = path.join(workspace, `tickets-${runId}-update.json`);
|
|
738
|
+
fs.writeFileSync(ticketUpdateApprovalPath, `${JSON.stringify({
|
|
739
|
+
command: "myte feedback tickets update",
|
|
740
|
+
reason,
|
|
741
|
+
feedback_id: documentSetFeedbackId,
|
|
742
|
+
ticket_ids: ticketIds,
|
|
743
|
+
batch_count: ticketIds.length,
|
|
744
|
+
proposed_change: { status: "in_progress" },
|
|
745
|
+
}, null, 2)}\n`, "utf8");
|
|
746
|
+
const ticketUpdate = runCli([
|
|
747
|
+
"feedback", "tickets", "update",
|
|
748
|
+
"--feedback-id", documentSetFeedbackId,
|
|
749
|
+
"--ticket-ids", ticketIds.join(","),
|
|
750
|
+
"--status", "in_progress",
|
|
751
|
+
"--confirm-write", "--approval-artifact", ticketUpdateApprovalPath,
|
|
752
|
+
"--idempotency-key", `ticket-update-${runId}`,
|
|
753
|
+
"--json", ...baseArgs,
|
|
754
|
+
], workspace, { apiKey: collaboratorWriteKey }).stdout;
|
|
755
|
+
assert(ticketUpdate.updated_count === 2, "Ticket batch update did not update both items.");
|
|
756
|
+
if (ticketUpdate.batch_id) {
|
|
757
|
+
recordCertificationArtifact(manifest, {
|
|
758
|
+
kind: "ticket_batch",
|
|
759
|
+
id: String(ticketUpdate.batch_id),
|
|
760
|
+
metadata: { operation: "update", feedback_id: documentSetFeedbackId },
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
const ticketList = runCli([
|
|
764
|
+
"feedback", "tickets", "list",
|
|
765
|
+
"--feedback-id", documentSetFeedbackId,
|
|
766
|
+
"--json", ...baseArgs,
|
|
767
|
+
], workspace, { apiKey: collaboratorWriteKey }).stdout;
|
|
768
|
+
assert(
|
|
769
|
+
ticketIds.every((ticketId) => ticketList.tickets?.some((ticket) => String(ticket._id || ticket.ticket_id) === ticketId && ticket.status === "in_progress")),
|
|
770
|
+
"Ticket list did not reflect the batch lifecycle update.",
|
|
771
|
+
);
|
|
772
|
+
const ticketCoverageApprovalPath = path.join(workspace, `tickets-${runId}-coverage.json`);
|
|
773
|
+
fs.writeFileSync(ticketCoverageApprovalPath, `${JSON.stringify({
|
|
774
|
+
command: "myte feedback tickets coverage",
|
|
775
|
+
reason,
|
|
776
|
+
feedback_id: documentSetFeedbackId,
|
|
777
|
+
ticket_id: ticketIds[0],
|
|
778
|
+
version_id: ticketVersionId,
|
|
779
|
+
document_id: ticketDocumentId,
|
|
780
|
+
coverage_status: "partially_covered",
|
|
781
|
+
}, null, 2)}\n`, "utf8");
|
|
782
|
+
const ticketCoverage = runCli([
|
|
783
|
+
"feedback", "tickets", "coverage",
|
|
784
|
+
"--feedback-id", documentSetFeedbackId,
|
|
785
|
+
"--ticket-id", ticketIds[0],
|
|
786
|
+
"--version-id", ticketVersionId,
|
|
787
|
+
"--document-id", ticketDocumentId,
|
|
788
|
+
"--coverage-status", "partially_covered",
|
|
789
|
+
"--confirm-write", "--approval-artifact", ticketCoverageApprovalPath,
|
|
790
|
+
"--idempotency-key", `ticket-coverage-${runId}`,
|
|
791
|
+
"--json", ...baseArgs,
|
|
792
|
+
], workspace, { apiKey: collaboratorWriteKey }).stdout;
|
|
793
|
+
assert(
|
|
794
|
+
ticketCoverage.prd_links?.some((link) => String(link.version_id) === ticketVersionId && String(link.document_id) === ticketDocumentId && link.coverage_status === "partially_covered"),
|
|
795
|
+
"Ticket coverage update did not persist on the expected PRD link.",
|
|
796
|
+
);
|
|
797
|
+
runCli(["feedback-sync", "--json", ...baseArgs], workspace, { apiKey: collaboratorWriteKey });
|
|
798
|
+
const syncedTicketItem = findFeedbackItem(workspace, documentSetFeedbackId);
|
|
799
|
+
assert(
|
|
800
|
+
syncedTicketItem?.tickets?.length >= 2 && syncedTicketItem.ticket_count >= 2,
|
|
801
|
+
"feedback-sync did not hydrate ticket summaries.",
|
|
802
|
+
);
|
|
803
|
+
writeCertificationManifest(manifestPath, manifest);
|
|
804
|
+
|
|
660
805
|
const commentApprovalPath = writeCommentApproval(
|
|
661
806
|
workspace,
|
|
662
807
|
runId,
|
|
@@ -8,6 +8,7 @@ const { spawnSync } = require("node:child_process");
|
|
|
8
8
|
|
|
9
9
|
const CLI_PATH = path.resolve(__dirname, "..", "cli.js");
|
|
10
10
|
const DEFAULT_BASE_URL = "https://api.myte.dev/api";
|
|
11
|
+
const PACKAGE_VERSION = require("../package.json").version;
|
|
11
12
|
|
|
12
13
|
function parseArgs(argv) {
|
|
13
14
|
const args = { _: [] };
|
|
@@ -285,7 +286,7 @@ class Harness {
|
|
|
285
286
|
this.key = getProjectKey();
|
|
286
287
|
this.actorBase = String(args["actor-scope"] || `mission-live-full-${nowId()}`);
|
|
287
288
|
this.cliMode = String(args.cli || "local").toLowerCase();
|
|
288
|
-
this.packageVersion = String(args["package-version"] ||
|
|
289
|
+
this.packageVersion = String(args["package-version"] || PACKAGE_VERSION);
|
|
289
290
|
this.batchSize = Math.max(1, Math.min(10, Number(args["batch-size"] || 10)));
|
|
290
291
|
this.includeQaqcRun = args["include-qaqc-run"] === true;
|
|
291
292
|
this.workspace = path.resolve(
|
|
@@ -433,7 +434,7 @@ class Harness {
|
|
|
433
434
|
change_set: { description: "Harness proposed description. This should be rejected during cleanup." },
|
|
434
435
|
}],
|
|
435
436
|
});
|
|
436
|
-
const first = this.cli(["suggestions", "create", "--file", createOne, "--no-sync", "--json"], { actorScope: actor });
|
|
437
|
+
const first = this.cli(["suggestions", "create", "--file", createOne, "--confirm-write", "--approval-artifact", createOne, "--no-sync", "--json"], { actorScope: actor });
|
|
437
438
|
const suggestionId = pickSuggestionId(first);
|
|
438
439
|
assertCondition(suggestionId, "Update suggestion create did not return suggestion_id.");
|
|
439
440
|
this.openSuggestions.add(suggestionId);
|
|
@@ -446,7 +447,7 @@ class Harness {
|
|
|
446
447
|
change_set: { acceptance_criteria: ["Harness proposed acceptance criterion. This should be rejected."] },
|
|
447
448
|
}],
|
|
448
449
|
});
|
|
449
|
-
const second = this.cli(["suggestions", "create", "--file", createTwo, "--no-sync", "--json"], { actorScope: actor });
|
|
450
|
+
const second = this.cli(["suggestions", "create", "--file", createTwo, "--confirm-write", "--approval-artifact", createTwo, "--no-sync", "--json"], { actorScope: actor });
|
|
450
451
|
const appendedId = pickSuggestionId(second);
|
|
451
452
|
assertCondition(appendedId === suggestionId, `Expected append to same suggestion ${suggestionId}, got ${appendedId || "(none)"}.`);
|
|
452
453
|
|
|
@@ -457,7 +458,7 @@ class Harness {
|
|
|
457
458
|
change_set: { technical_requirements: ["Harness proposed requirement. This should be rejected."] },
|
|
458
459
|
}],
|
|
459
460
|
});
|
|
460
|
-
const revised = this.cli(["suggestions", "revise", "--file", revise, "--no-sync", "--json"], { actorScope: actor });
|
|
461
|
+
const revised = this.cli(["suggestions", "revise", "--file", revise, "--confirm-write", "--approval-artifact", revise, "--no-sync", "--json"], { actorScope: actor });
|
|
461
462
|
assertCondition((revised.revised_count || 0) >= 1, "Update suggestion revise did not revise the thread.");
|
|
462
463
|
|
|
463
464
|
const requestChanges = writeJson(this.payloadDir, "update-loop-request-changes.json", {
|
|
@@ -473,7 +474,7 @@ class Harness {
|
|
|
473
474
|
change_set: { labels: ["harness-proposed-update"] },
|
|
474
475
|
}],
|
|
475
476
|
});
|
|
476
|
-
const revisedAgain = this.cli(["suggestions", "revise", "--file", reviseAfterRequest, "--no-sync", "--json"], { actorScope: actor });
|
|
477
|
+
const revisedAgain = this.cli(["suggestions", "revise", "--file", reviseAfterRequest, "--confirm-write", "--approval-artifact", reviseAfterRequest, "--no-sync", "--json"], { actorScope: actor });
|
|
477
478
|
assertCondition((revisedAgain.revised_count || 0) >= 1, "Update suggestion revise after request_changes did not process.");
|
|
478
479
|
|
|
479
480
|
const reject = writeJson(this.payloadDir, "update-loop-reject.json", {
|
|
@@ -504,7 +505,7 @@ class Harness {
|
|
|
504
505
|
},
|
|
505
506
|
}],
|
|
506
507
|
});
|
|
507
|
-
const created = this.cli(["suggestions", "create", "--file", createFile, "--no-sync", "--json"], { actorScope: actor });
|
|
508
|
+
const created = this.cli(["suggestions", "create", "--file", createFile, "--confirm-write", "--approval-artifact", createFile, "--no-sync", "--json"], { actorScope: actor });
|
|
508
509
|
const suggestionId = pickSuggestionId(created);
|
|
509
510
|
assertCondition(suggestionId, "Create suggestion did not return suggestion_id.");
|
|
510
511
|
this.openSuggestions.add(suggestionId);
|
|
@@ -522,7 +523,7 @@ class Harness {
|
|
|
522
523
|
change_set: { description: "Harness revised proposal. This should still be rejected." },
|
|
523
524
|
}],
|
|
524
525
|
});
|
|
525
|
-
const revised = this.cli(["suggestions", "revise", "--file", reviseFile, "--no-sync", "--json"], { actorScope: actor });
|
|
526
|
+
const revised = this.cli(["suggestions", "revise", "--file", reviseFile, "--confirm-write", "--approval-artifact", reviseFile, "--no-sync", "--json"], { actorScope: actor });
|
|
526
527
|
assertCondition((revised.revised_count || 0) >= 1, "Create suggestion revise did not process.");
|
|
527
528
|
|
|
528
529
|
const requestChanges = writeJson(this.payloadDir, "create-reject-request-changes.json", {
|
|
@@ -579,7 +580,7 @@ class Harness {
|
|
|
579
580
|
},
|
|
580
581
|
}],
|
|
581
582
|
});
|
|
582
|
-
const created = this.cli(["suggestions", "create", "--file", createFile, "--no-sync", "--json"], { actorScope: actor, timeoutMs: 180000 });
|
|
583
|
+
const created = this.cli(["suggestions", "create", "--file", createFile, "--confirm-write", "--approval-artifact", createFile, "--no-sync", "--json"], { actorScope: actor, timeoutMs: 180000 });
|
|
583
584
|
const suggestionId = pickSuggestionId(created);
|
|
584
585
|
assertCondition(suggestionId, "Approved mission create did not return suggestion_id.");
|
|
585
586
|
this.openSuggestions.add(suggestionId);
|
|
@@ -633,7 +634,7 @@ class Harness {
|
|
|
633
634
|
change_set: { description: "Harness pending suggestion should be hidden from actionable queue while archived." },
|
|
634
635
|
}],
|
|
635
636
|
});
|
|
636
|
-
const pending = this.cli(["suggestions", "create", "--file", pendingFile, "--no-sync", "--json"], { actorScope: actor, timeoutMs: 180000 });
|
|
637
|
+
const pending = this.cli(["suggestions", "create", "--file", pendingFile, "--confirm-write", "--approval-artifact", pendingFile, "--no-sync", "--json"], { actorScope: actor, timeoutMs: 180000 });
|
|
637
638
|
pendingSuggestionId = pickSuggestionId(pending);
|
|
638
639
|
assertCondition(pendingSuggestionId, "Pending update suggestion for approved mission was not created.");
|
|
639
640
|
this.openSuggestions.add(pendingSuggestionId);
|