@tea-agent/loop-agent 0.42.0-next.13 → 0.42.0-next.15

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.
Files changed (103) hide show
  1. package/CHANGELOG.md +25 -2
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/executors/dag-pi-executor.js +617 -94
  4. package/dist/executors/shell-executor.js +4 -0
  5. package/dist/worker/console/chat/pi-runtime.js +45 -2
  6. package/dist/worker/console/chat/resource-loader.js +4 -1
  7. package/dist/worker/console/chat/routes.js +22 -11
  8. package/dist/worker/console/chat/sdd-data-alignment.js +13 -2
  9. package/dist/worker/console/chat/session-store.js +5 -1
  10. package/dist/worker/console/chat/subagents/agent-tool.js +62 -0
  11. package/dist/worker/console/chat/subagents/explore-agent.js +169 -0
  12. package/dist/worker/console/chat/subagents/index.js +5 -0
  13. package/dist/worker/console/chat/subagents/orchestrator.js +273 -0
  14. package/dist/worker/console/chat/subagents/tool-policy.js +53 -0
  15. package/dist/worker/console/chat/subagents/types.js +13 -0
  16. package/dist/worker/console/chat/tool-preview.js +10 -0
  17. package/dist/worker/console/chat/tools.js +11 -1
  18. package/dist/worker/console/chat/turn-process.js +1 -0
  19. package/dist/worker/console/interview/tools.js +1 -0
  20. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-BZogYNl1.js → abnfDiagram-N423BO3Z-CgXb0EVO.js} +1 -1
  21. package/dist/worker/console/static/assets/{arc-DcJTLe2v.js → arc-DN59MZqN.js} +1 -1
  22. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-B39EQQ9n.js → architectureDiagram-T3A2C74G-BUk3sWpn.js} +1 -1
  23. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CitCGV56.js → blockDiagram-VBNYF7ZC-IH-cPBFE.js} +1 -1
  24. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-rvWuOHLG.js → c4Diagram-5PPSVZJV-BJWf1nGo.js} +1 -1
  25. package/dist/worker/console/static/assets/channel-i1DjpDIw.js +1 -0
  26. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DGXplIJs.js → chunk-2GRJ4B5K-BCPb5H0y.js} +1 -1
  27. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-ur9OqjPn.js → chunk-2Q5K7J3B-Cfs3jeW2.js} +1 -1
  28. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-D1KqU_Vi.js → chunk-5RXB4S5H-BhQI1B_T.js} +1 -1
  29. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BlVZrbtM.js → chunk-5VM5RSS4-Cc_m4gyV.js} +1 -1
  30. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BAzz3nQy.js → chunk-6Q2QTUOP-JPqDS3IV.js} +1 -1
  31. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CP_nYuCV.js → chunk-GF5L2VYU-AeGX6EAg.js} +1 -1
  32. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CWvKQ80X.js → chunk-JWPE2WC7-pEyTjekV.js} +1 -1
  33. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CyUki8wp.js → chunk-KBJHAD2P-Bi5UopKd.js} +1 -1
  34. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-5NYzNKfY.js → chunk-RYQCIY6F-FkGFJxgQ.js} +1 -1
  35. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DHdUgjS-.js → chunk-XXDRQBXY-D-7LGrV2.js} +1 -1
  36. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DgDRdE1V.js +1 -0
  37. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DgDRdE1V.js +1 -0
  38. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-ANQ5g_t6.js → cose-bilkent-JH36ORCC-CCEDNDaX.js} +1 -1
  39. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-CruT_4-0.js → cynefin-VYW2F7L2-DDd-t7fm.js} +1 -1
  40. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-rbFo77ID.js → cynefinDiagram-MW4NZA55-LWe4Ikzr.js} +1 -1
  41. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-asstxBQs.js → dagre-VZM6K2ZE-BBCZScc-.js} +1 -1
  42. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-DzTyBZwI.js → diagram-7IWD3JNH-B6liRVig.js} +1 -1
  43. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-gw8ccH3B.js → diagram-B4RE2ZJO-DO_hIrpW.js} +1 -1
  44. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-B8RpZzOf.js → diagram-LBJQPF4R-dmCy93uR.js} +1 -1
  45. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-B1zJkCS9.js → diagram-Q27KOJAE-D6mFTIxP.js} +1 -1
  46. package/dist/worker/console/static/assets/{diagram-UB23O5K3-B6JLWZmO.js → diagram-UB23O5K3-DCteVUfY.js} +1 -1
  47. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-q2iZP-Ps.js → ebnfDiagram-BXEA7PRR-DTv530VK.js} +1 -1
  48. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-B3dbbktQ.js → erDiagram-JOGREHBK-DCXDMxCr.js} +1 -1
  49. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-C-zc6-kB.js → flowDiagram-UKHOOZJN-BwEBLOJh.js} +1 -1
  50. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BSolnot9.js → ganttDiagram-PKOTCBZU-Ck-Vymjm.js} +1 -1
  51. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bo8jGxTk.js → gitGraphDiagram-DS77QQ5N-Hqs6X_3L.js} +1 -1
  52. package/dist/worker/console/static/assets/{index-DhfjOafu.js → index-BmMi-Bve.js} +82 -82
  53. package/dist/worker/console/static/assets/{index-CAZ2fC_X.css → index-Dh0Gh4X0.css} +1 -1
  54. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DQaZqJOH.js → infoDiagram-6WML65LV-Cjc6M9eg.js} +1 -1
  55. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DsdX1WnE.js → ishikawaDiagram-WSZJBQD7-CPchYZMl.js} +1 -1
  56. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CP5EYDZL.js → journeyDiagram-NVQOT4AX-BABdJNNC.js} +1 -1
  57. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DAm14Dr8.js → kanban-definition-27J2QSJJ-1oXhbM4j.js} +1 -1
  58. package/dist/worker/console/static/assets/{linear-gZECoLc5.js → linear-PTmQ9LkV.js} +1 -1
  59. package/dist/worker/console/static/assets/{mermaid.core-BRJNIM6p.js → mermaid.core-B6Lxil0V.js} +5 -5
  60. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-Cja3kLkR.js → mindmap-definition-FAOFIHXS-BUqjNGEw.js} +1 -1
  61. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-22ZGFisL.js → pegDiagram-VL7TDLO6-8D1N-orJ.js} +1 -1
  62. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BXin0Y1o.js → pieDiagram-7S7Q4E2Y-BlPMN9d9.js} +1 -1
  63. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Cw6T69Yt.js → quadrantDiagram-CIZ2JOQS-BIL5YDes.js} +1 -1
  64. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-C1-gTieN.js → railroadDiagram-AXF67PYL-Dqmil3ie.js} +1 -1
  65. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP--H5N2iI1.js → requirementDiagram-LRYGKXZP-C_-Dp4mH.js} +1 -1
  66. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-CgWAPeRz.js → sankeyDiagram-W5VNT64P-C0s5-bQS.js} +1 -1
  67. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CrKqzGvt.js → sequenceDiagram-SI44F4Z6-DiVCHPfi.js} +1 -1
  68. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-BB3wG06K.js → sizeCapture-X5ZJPWSS-CxQ9WVvx.js} +1 -1
  69. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-DjsGgdgY.js → stateDiagram-OKZ733FA-D9mFHA-Y.js} +1 -1
  70. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BqXQxfFC.js +1 -0
  71. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DYKEbvAR.js → swimlanes-SLNWSIFB-DDnC5l-M.js} +2 -2
  72. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CXwWNRJl.js +8 -0
  73. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-eQOb5k9Y.js → timeline-definition-Z64GVDOM-C8QySPC-.js} +1 -1
  74. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-B2-l9FIu.js → vennDiagram-T6HMQDX7-BeYdDiz6.js} +1 -1
  75. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-BX2Cda3l.js → wardleyDiagram-T6FBY63Y-D8hjFWLH.js} +1 -1
  76. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-D9S892ph.js → xychartDiagram-ELKLHX3M-ClqG_JGK.js} +1 -1
  77. package/dist/worker/console/static/index.html +2 -2
  78. package/dist/worker/console/static-src/chat-view-types.js +1 -1
  79. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +23 -0
  80. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +32 -0
  81. package/dist/worker/console/static-src/operator-chat/tools-catalog.js +21 -2
  82. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +2 -0
  83. package/dist/worker/console/static-src/operator-chat/useChatStream.js +30 -14
  84. package/dist/worker/console/static-src/operator-chat/useChatThread.js +21 -1
  85. package/dist/workflows/dag/frontend-contract-facts.js +130 -0
  86. package/dist/workflows/dag/frontend-design-policy.js +99 -14
  87. package/dist/workflows/dag/frontend-implementation-contract.js +56 -8
  88. package/dist/workflows/dag/frontend-plan-render.js +13 -2
  89. package/dist/workflows/dag/frontend-shadow-dual-write.js +1 -0
  90. package/dist/workflows/dag/frontend-typed-event-store.js +3 -0
  91. package/dist/workflows/dag/init-hybrid.js +7 -3
  92. package/dist/workflows/dag/node-execution.js +54 -16
  93. package/docs/operations/README.md +1 -0
  94. package/docs/templates/frontend-implementation-contract.schema.json +34 -2
  95. package/harness.json +1 -1
  96. package/package.json +2 -3
  97. package/skills/frontend-plan/SKILL.md +8 -0
  98. package/skills/frontend-plan/references/decision-contract.md +26 -3
  99. package/dist/worker/console/static/assets/channel-CXqdP5pW.js +0 -1
  100. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D9C3agF7.js +0 -1
  101. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D9C3agF7.js +0 -1
  102. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Tp7V0U4q.js +0 -1
  103. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DUZWZWi8.js +0 -8
@@ -21,6 +21,7 @@ import "./contract-validator-registrations.js";
21
21
  import { computeNormalizedFailureFingerprint } from "./frontend-recovery-lineage.js";
22
22
  import { parseLedgerJson } from "../../task/source-prepare/ledger.js";
23
23
  import { readTypedEventStoreFromJsonl } from "./frontend-typed-event-store.js";
24
+ import { collectCanonicalStateFlowNames, extractRequiredDeliverablePaths, resolveFrontendContractRequirements, } from "./frontend-contract-facts.js";
24
25
  import { allowedRepairReadPaths, auditRepairAttemptToolUse, buildStructuredOutputRepairPrompt, freezeStructuredOutputRepairContext, hasNonEmptyStructuredCandidate, isFrontendStructuredRepairSchemaId, isStructuredRepairableFailureCategory, persistStructuredAttemptRaw, sessionEventsByteLength, GOVERNANCE_BLOCKED_CATEGORY, STRUCTURED_REPAIR_EXHAUSTED_CATEGORY, } from "./structured-output-repair.js";
25
26
  import { readFrontendCanonicalCandidate } from "./frontend-implementation-contract.js";
26
27
  import { writeDagNodeJsonArtifact } from "../../infrastructure/harness/artifact-store.js";
@@ -325,6 +326,8 @@ const FRONTEND_CONTRACT_RECORD_TOOL_NAMES_LOCAL = new Set([
325
326
  "record_handoff_intent",
326
327
  "record_open_question",
327
328
  "record_split_proposal",
329
+ "record_ui_state",
330
+ "record_required_deliverables",
328
331
  ]);
329
332
  async function countContractRecordSubmissions(runDir, nodeId) {
330
333
  const eventsPath = path.join(runDir, nodeId, "session-events.jsonl");
@@ -553,8 +556,9 @@ export function renderFrontendPlanInputContext(input) {
553
556
  : []);
554
557
  const contractFacts = committedFacts(input.contractRecords);
555
558
  const scoutFacts = committedFacts(input.scoutRecords);
556
- const requirements = contractFacts
557
- .filter((fact) => fact.kind === "requirement" && fact.origin === "contract")
559
+ const requirementFacts = resolveFrontendContractRequirements(contractFacts);
560
+ const requiredDeliverables = extractRequiredDeliverablePaths(contractFacts);
561
+ const requirements = requirementFacts
558
562
  .map((fact) => ({
559
563
  id: planInputText(fact.id, 80),
560
564
  text: planInputText(fact.text),
@@ -580,19 +584,28 @@ export function renderFrontendPlanInputContext(input) {
580
584
  paths: fact.paths,
581
585
  conflicts: fact.conflicts,
582
586
  }));
587
+ // Authoritative UI states (contract-declared): the source's UI-state table
588
+ // extracted by the contract node. The planner binds these ids instead of
589
+ // inventing list-visibility variants.
590
+ const declaredUiStates = contractFacts
591
+ .filter((fact) => fact.kind === "ui-state-declaration" && fact.origin === "contract")
592
+ .map((fact) => ({
593
+ id: planInputText(fact.id, 80),
594
+ trigger: planInputText(fact.trigger),
595
+ observableOutcome: planInputText(fact.observableOutcome),
596
+ }))
597
+ .filter((state) => state.id !== undefined);
598
+ // Replay registry edits and state-flow removals/additions in commit order.
599
+ const committedUxNames = collectCanonicalStateFlowNames(input.planRecords ?? [], true);
600
+ const committedUiStateNames = [...committedUxNames.uiStateNames];
601
+ const committedInteractionNames = [...committedUxNames.interactionNames];
583
602
  // Reviewer-rubric scaffold: the design reviewer re-runs the design-policy
584
603
  // checks on the committed facts, so publish the checklist to the producer.
585
604
  // Requirements whose contract evidence expects behavioural verification are
586
605
  // enumerated explicitly — those are the slots the reviewer finds missing
587
606
  // when the plan models interactions ad hoc (r8/r9 findings).
588
- const behaviorRequiredIds = requirements
589
- .filter((requirement) => {
590
- const fact = contractFacts.find((candidate) => candidate.kind === "requirement" &&
591
- candidate.origin === "contract" &&
592
- candidate.id === requirement.id);
593
- const evidence = fact?.evidence;
594
- return evidence?.behavior === "required";
595
- })
607
+ const behaviorRequiredIds = requirementFacts
608
+ .filter((requirement) => requirement.evidence.behavior === "required")
596
609
  .map((requirement) => requirement.id);
597
610
  const serializeAtCap = (cap) => JSON.stringify({
598
611
  requirements: requirements.map((requirement) => ({
@@ -600,6 +613,7 @@ export function renderFrontendPlanInputContext(input) {
600
613
  text: planInputText(requirement.text, cap.text),
601
614
  sourceFragmentIds: planInputStrings(requirement.sourceFragmentIds).slice(0, cap.array),
602
615
  })),
616
+ requiredDeliverables,
603
617
  targetSurface: targetSurface.map((surface) => ({
604
618
  completeness: planInputText(surface.completeness, 32),
605
619
  entrypoint: planInputText(surface.entrypoint, cap.text),
@@ -615,6 +629,18 @@ export function renderFrontendPlanInputContext(input) {
615
629
  paths: planInputStrings(evidence.paths).slice(0, cap.array),
616
630
  conflicts: planInputStrings(evidence.conflicts).slice(0, cap.array),
617
631
  })),
632
+ declaredUiStates: declaredUiStates.map((state) => ({
633
+ id: state.id,
634
+ trigger: planInputText(state.trigger, cap.text),
635
+ observableOutcome: planInputText(state.observableOutcome, cap.text),
636
+ })),
637
+ committedUx: committedUiStateNames.length > 0 ||
638
+ committedInteractionNames.length > 0
639
+ ? {
640
+ uiStateNames: committedUiStateNames,
641
+ interactionNames: committedInteractionNames,
642
+ }
643
+ : undefined,
618
644
  });
619
645
  let serialized = serializeAtCap(FRONTEND_PLAN_INPUT_CAP_LADDER[0]);
620
646
  for (const cap of FRONTEND_PLAN_INPUT_CAP_LADDER.slice(1)) {
@@ -628,6 +654,7 @@ export function renderFrontendPlanInputContext(input) {
628
654
  // to the minimum, and declare the degradation instead of corrupting JSON.
629
655
  let fallback = {
630
656
  degraded: "requirement-texts-truncated",
657
+ requiredDeliverables,
631
658
  requirements: requirements.map((requirement) => ({
632
659
  id: requirement.id,
633
660
  text: "(truncated)",
@@ -652,20 +679,20 @@ export function renderFrontendPlanInputContext(input) {
652
679
  serialized = bounded;
653
680
  }
654
681
  const checklistLines = [
655
- "1. Every interaction you record needs a uiComponentChoices entry whose purpose equals the interaction name, or one decision=reuse-existing choice covering behavioural interactions.",
656
- "2. Every applicable UI state needs a purpose-matching component choice or a stylingStrategy.",
657
- "3. Every requirement marked (behavior) below needs modelled interactions plus at least one verification target that references it.",
658
- "4. targets.files must name the concrete deliverable files; never leave the scope broader than the frozen requirements state.",
682
+ "1. Record the GLOBAL UX vocabulary with record_state_registry BEFORE any record_state_flow: one stable behavior-domain name per state/interaction (e.g. planner-task-edit), never one name per AC number, and never a rename of an already-recorded concept. Coverage slices by AC; UX does not.",
683
+ "2. Every recorded interaction/uiState name must be in that registry, and uiState names must use the contract's declared authoritative ids (declaredUiStates below) when present.",
684
+ "3. Every interaction and every applicable UI state must be covered by a uiComponentChoices entry: its purpose equals the name, or the choice lists the name in covers (one choice may cover many ids). A reuse-existing decision without evidencePath is rejected; stylingStrategy alone covers nothing.",
685
+ "4. Every requirement marked (behavior) below needs modelled interactions plus at least one verification target that references it.",
659
686
  "5. Verification targets may only reference UI states and requirements you actually recorded (the record_* tools reject unknown references).",
660
687
  `Requirements requiring behavioural coverage: ${behaviorRequiredIds.length > 0 ? behaviorRequiredIds.join(", ") : "(none)"}`,
661
- "6. A decision=new component must declare sourceRequirementIds and pass sourceFragmentId for the frozen PRD fragment whose section matches the component's purpose — the runtime validates that binding and derives specReference (path/section/line); the reviewer checks purpose↔citation consistency.",
688
+ "6. A decision=new component must declare sourceRequirementIds and pass sourceFragmentId for the frozen PRD fragment whose section matches the component's purpose — the runtime validates that binding and derives specReference (path/section/line); the reviewer checks purpose↔citation consistency. A decision=reuse-existing component must pass evidencePath pointing at the existing repo file that proves the reuse.",
662
689
  ...[...input.componentSourceCitations ?? []]
663
690
  .filter(([id]) => behaviorRequiredIds.includes(id))
664
691
  .flatMap(([id, citations]) => citations.map((citation) => ` ${id} + ${citation.fragmentId} → ${citation.section}${citation.line ? ` (line ${citation.line})` : ""}`)),
665
692
  ];
666
693
  return [
667
694
  "<frontend_plan_input>",
668
- "Committed Contract/Scout facts, compiled by the runner. Treat them as the complete planning evidence.",
695
+ "Committed Contract/Scout facts, compiled by the runner. Treat them as the complete planning evidence. declaredUiStates are the authoritative UI states from the task source; committedUx (retry attempts) is the UX vocabulary already recorded — reuse those names, never re-invent them.",
669
696
  serialized,
670
697
  "Do not read upstream artifacts, task sources, or repository files. If this input cannot support a decision, record a genuine evidence gap.",
671
698
  "</frontend_plan_input>",
@@ -692,6 +719,16 @@ export async function buildFrontendPlanInputContext(runDir, componentSourceCitat
692
719
  // forbids reading anything.
693
720
  throw new Error(`frontend-plan-input-unavailable: cannot read committed typed facts (${error instanceof Error ? error.message : String(error)})`);
694
721
  }
722
+ // Retry-attempt continuity (UX slice visibility): the plan node's own
723
+ // committed facts are absent on the first attempt and present on retries;
724
+ // a missing file is normal there, not a broken pipeline.
725
+ let planRecords = [];
726
+ try {
727
+ planRecords = await readTypedEventStoreFromJsonl(path.join(runDir, "frontend-plan-pi", "plan-typed-facts.jsonl"));
728
+ }
729
+ catch {
730
+ planRecords = [];
731
+ }
695
732
  const committedCount = [...contractRecords, ...scoutRecords].filter((record) => record.phase === "committed").length;
696
733
  if (committedCount === 0) {
697
734
  throw new Error(`frontend-plan-input-unavailable: no committed Contract/Scout facts in ${contractFactsPath} / ${scoutFactsPath}`);
@@ -699,6 +736,7 @@ export async function buildFrontendPlanInputContext(runDir, componentSourceCitat
699
736
  return renderFrontendPlanInputContext({
700
737
  contractRecords,
701
738
  scoutRecords,
739
+ planRecords,
702
740
  componentSourceCitations,
703
741
  });
704
742
  }
@@ -11,5 +11,6 @@
11
11
  - [`production-readiness.md`](production-readiness.md):交付前的生产就绪判断。
12
12
  - [`agent-worker-production-readiness.md`](agent-worker-production-readiness.md):agent-worker Feature/Task Pool 外层编排的 Production Readiness v1 操作合同。
13
13
  - [`backend-test-jacoco-coverage.md`](backend-test-jacoco-coverage.md):Java 被测服务挂载 JaCoCo tcpserver agent 的 Maven、`java -jar` 与 Docker 操作手册。
14
+ - [`console-chat-dogfood-playbook.md`](console-chat-dogfood-playbook.md):Operator Chat(含 Explore 子 Agent)真实模型 dogfood 的 CLI 驱动步骤、mutation 双 token / SSE 超时 / question 应答等已知陷阱与验证方式。
14
15
 
15
16
  验证命令仍以 [`../governance/verification-matrix.md`](../governance/verification-matrix.md) 为准。
@@ -58,6 +58,12 @@
58
58
  "type": "string",
59
59
  "minLength": 1
60
60
  }
61
+ },
62
+ "requiredDeliverables": {
63
+ "type": "array",
64
+ "items": {
65
+ "$ref": "#/$defs/path"
66
+ }
61
67
  }
62
68
  }
63
69
  },
@@ -433,8 +439,7 @@
433
439
  "required": [
434
440
  "purpose",
435
441
  "component",
436
- "decision",
437
- "rationale"
442
+ "decision"
438
443
  ],
439
444
  "properties": {
440
445
  "purpose": {
@@ -465,6 +470,16 @@
465
470
  "rationale": {
466
471
  "type": "string",
467
472
  "minLength": 1
473
+ },
474
+ "covers": {
475
+ "type": "array",
476
+ "items": {
477
+ "type": "string",
478
+ "minLength": 1
479
+ }
480
+ },
481
+ "evidencePath": {
482
+ "$ref": "#/$defs/path"
468
483
  }
469
484
  },
470
485
  "allOf": [
@@ -511,6 +526,23 @@
511
526
  }
512
527
  }
513
528
  }
529
+ },
530
+ {
531
+ "if": {
532
+ "properties": {
533
+ "decision": {
534
+ "const": "reuse-existing"
535
+ }
536
+ },
537
+ "required": [
538
+ "decision"
539
+ ]
540
+ },
541
+ "then": {
542
+ "required": [
543
+ "evidencePath"
544
+ ]
545
+ }
514
546
  }
515
547
  ]
516
548
  }
package/harness.json CHANGED
@@ -82,7 +82,7 @@
82
82
  "executors": {
83
83
  "pi": {
84
84
  "description": "Pi 负责规划、评审、诊断;当 DAG toolProfile=write 时也可做有界写入。模型按复杂度三档配置,支持 provider/model 字符串或带 thinking 的对象;斜杠前为 Pi provider,后为 modelId,勿只写裸 modelId。",
85
- "LOW": "wizard-local/minimax-m3",
85
+ "LOW": "wizard-local/glm-5.3-flash",
86
86
  "MED": "wizard-local/glm-5.3",
87
87
  "HIGH": "wizard-local/gpt-5.6-sol"
88
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.42.0-next.13",
3
+ "version": "0.42.0-next.15",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",
@@ -107,6 +107,5 @@
107
107
  "typescript": "^5.9.3",
108
108
  "vite": "^7.0.0",
109
109
  "vitest": "^4.1.11"
110
- },
111
- "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
110
+ }
112
111
  }
@@ -21,6 +21,14 @@ requirement coverage, component/styling choices, applicable states and interacti
21
21
  data/Mock strategy, deviations, and dependency policy. Process a bounded requirement
22
22
  slice and record facts immediately rather than reasoning over the whole task first.
23
23
 
24
+ UX vocabulary is global, not per-requirement: commit `record_state_registry`
25
+ (one stable behavior-domain name per state/interaction) before any
26
+ `record_state_flow`, bind UI states to the contract's declared authoritative ids,
27
+ and let one component choice cover many ids via `covers`. `reuse-existing` must
28
+ cite `evidencePath` of an existing file; greenfield is `decision=new`.
29
+ Bind every file in the Contract-owned `requiredDeliverables` inventory. It records
30
+ explicit source obligations, not every path mentioned by a requirement.
31
+
24
32
  The runtime owns protected skeleton fields, path/command validation, materialization,
25
33
  and final schema checks. Finish with exactly one `finalize_plan`; return no Markdown
26
34
  narrative. Record a genuine evidence gap when frozen facts are insufficient.
@@ -36,12 +36,29 @@ the task's declared scope. Capabilities the task source lists as non-goals (e.g.
36
36
  responsive/mobile layout, animations) must not be promised here, and themes or
37
37
  CSS conventions must not be claimed without a Scout-confirmed repository fact.
38
38
 
39
+ ## UX vocabulary (registry first)
40
+
41
+ - Record `record_state_registry` BEFORE any `record_state_flow`: one compact
42
+ global vocabulary of UI-state and interaction names. Coverage may slice by
43
+ requirement; UX must not — never one name per requirement number and never a
44
+ rename of an already-recorded concept (kebab-case behavior-domain names, e.g.
45
+ `planner-task-edit`, `focus-queue-move`).
46
+ - UI states use the contract's declared authoritative ids (`declaredUiStates`
47
+ in the plan input) when the source declares a state table.
48
+ - Retry slices see `committedUx` in the plan input: reuse those exact names.
49
+
39
50
  ## Global decisions
40
51
 
41
52
  Keep route/component placement, Mock/data strategy, and dependency/deviation policy
42
53
  as explicit global decisions rather than duplicating them across each requirement.
43
54
  Use only frozen command labels and Scout-confirmed paths.
44
55
 
56
+ Component choices: ONE choice may cover many UI states/interactions explicitly via
57
+ `covers` — never one row per interaction. `decision=reuse-existing` REQUIRES
58
+ `evidencePath` naming the existing repo file that proves the reuse (the runtime
59
+ verifies the file exists); a path that does not exist yet is greenfield and must
60
+ use `decision=new`.
61
+
45
62
  For Mock/API, keep the real request path enabled by default. Select only a strategy
46
63
  allowed by the frozen task capability. Active Mock requires deterministic Mock-backed
47
64
  verification and production-default-off activation. `not-needed` requires positive
@@ -54,6 +71,12 @@ widen the write set.
54
71
  ## Runtime-owned fields and terminal
55
72
 
56
73
  The runtime owns `schemaVersion`, `sourceBinding`, risk, canonical target files,
57
- aliases, command allowlisting, path containment, and final validation. Submit only
58
- editable decision facts, then call `finalize_plan` exactly once. The deterministic
59
- design policy materializes the canonical implementation contract.
74
+ `requiredDeliverables`, aliases, command allowlisting, path containment, and final
75
+ validation. Submit only editable decision facts, then call `finalize_plan` exactly
76
+ once. The deterministic design policy materializes the canonical implementation
77
+ contract: every file in the Contract's explicit source-bound delivery inventory
78
+ must be planned (`requiredDeliverables` gate). Permissions, prohibitions, examples
79
+ and read-only references do not create delivery obligations. Plan receives this
80
+ inventory as `requiredDeliverables`; it cannot add, remove or reinterpret it.
81
+ Missing files and UX name collisions are reported by finalize_plan before commit
82
+ and checked again by the policy shell.
@@ -1 +0,0 @@
1
- import{ag as o,ah as n}from"./mermaid.core-BRJNIM6p.js";const t=(a,r)=>o.lang.round(n.parse(a)[r]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-CP_nYuCV.js";import{_ as i}from"./mermaid.core-BRJNIM6p.js";import"./chunk-5VM5RSS4-BlVZrbtM.js";import"./chunk-XXDRQBXY-DHdUgjS-.js";import"./chunk-KBJHAD2P-CyUki8wp.js";import"./chunk-2GRJ4B5K-DGXplIJs.js";import"./index-DhfjOafu.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-CP_nYuCV.js";import{_ as i}from"./mermaid.core-BRJNIM6p.js";import"./chunk-5VM5RSS4-BlVZrbtM.js";import"./chunk-XXDRQBXY-DHdUgjS-.js";import"./chunk-KBJHAD2P-CyUki8wp.js";import"./chunk-2GRJ4B5K-DGXplIJs.js";import"./index-DhfjOafu.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{s as r,b as e,a,S as s}from"./chunk-5RXB4S5H-D1KqU_Vi.js";import{_ as i}from"./mermaid.core-BRJNIM6p.js";import"./chunk-XXDRQBXY-DHdUgjS-.js";import"./chunk-KBJHAD2P-CyUki8wp.js";import"./chunk-2GRJ4B5K-DGXplIJs.js";import"./index-DhfjOafu.js";var u={parser:a,get db(){return new s(2)},renderer:e,styles:r,init:i(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1,8 +0,0 @@
1
- import{c as r,s as e}from"./flowDiagram-UKHOOZJN-C-zc6-kB.js";import{_ as a}from"./mermaid.core-BRJNIM6p.js";import"./chunk-5VM5RSS4-BlVZrbtM.js";import"./chunk-XXDRQBXY-DHdUgjS-.js";import"./chunk-KBJHAD2P-CyUki8wp.js";import"./chunk-2GRJ4B5K-DGXplIJs.js";import"./channel-CXqdP5pW.js";import"./index-DhfjOafu.js";var o=a(t=>`${e(t)}
2
- .swimlane.cluster rect {
3
- stroke: ${t.clusterBorder} !important;
4
- }
5
- [data-look="neo"].cluster rect {
6
- filter: none;
7
- }
8
- `,"getStyles"),s=o,n=r({defaultLayout:"swimlane",styles:s});export{n as diagram};