@davesheffer/hunch 1.7.0 → 1.8.0

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 (71) hide show
  1. package/README.md +242 -0
  2. package/bench/constitution-exp03-v1.json +70 -0
  3. package/dist/cli/index.js +1630 -107
  4. package/dist/constitution/adapters.js +487 -0
  5. package/dist/constitution/behaviorAttestationBinding.js +17 -0
  6. package/dist/constitution/behaviorEvaluator.js +220 -0
  7. package/dist/constitution/behaviorProof.js +205 -0
  8. package/dist/constitution/behaviorWorkspace.js +124 -0
  9. package/dist/constitution/bootstrap.js +133 -0
  10. package/dist/constitution/canonical.js +51 -0
  11. package/dist/constitution/card.js +133 -0
  12. package/dist/constitution/compiler.js +176 -0
  13. package/dist/constitution/composition.js +101 -0
  14. package/dist/constitution/corpus.js +58 -0
  15. package/dist/constitution/delta.js +154 -0
  16. package/dist/constitution/disposition.js +141 -0
  17. package/dist/constitution/evaluator.js +435 -0
  18. package/dist/constitution/experiment.js +1007 -0
  19. package/dist/constitution/experimentRunner.js +344 -0
  20. package/dist/constitution/g2.js +291 -0
  21. package/dist/constitution/g2BehaviorAttestation.js +209 -0
  22. package/dist/constitution/g2BehaviorCandidates.js +703 -0
  23. package/dist/constitution/g2BehaviorDependencies.js +379 -0
  24. package/dist/constitution/g2BehaviorMaterialization.js +171 -0
  25. package/dist/constitution/g2BehaviorPolicyMaterializer.js +241 -0
  26. package/dist/constitution/g2CandidateAttestation.js +179 -0
  27. package/dist/constitution/g2Candidates.js +195 -0
  28. package/dist/constitution/g2Drills.js +122 -0
  29. package/dist/constitution/g3.js +511 -0
  30. package/dist/constitution/g3Conformance.js +132 -0
  31. package/dist/constitution/lifecycle.js +224 -0
  32. package/dist/constitution/mutation.js +262 -0
  33. package/dist/constitution/nodeTestEvidence.js +47 -0
  34. package/dist/constitution/plan.js +172 -0
  35. package/dist/constitution/policyRuntime.js +8 -0
  36. package/dist/constitution/proof.js +166 -0
  37. package/dist/constitution/repairPolicies.js +78 -0
  38. package/dist/constitution/replay.js +361 -0
  39. package/dist/constitution/replayCache.js +89 -0
  40. package/dist/constitution/replayWorker.js +34 -0
  41. package/dist/constitution/repository.js +533 -0
  42. package/dist/constitution/schema.js +545 -0
  43. package/dist/constitution/scorecard.js +106 -0
  44. package/dist/constitution/service.js +1211 -0
  45. package/dist/constitution/shadow.js +235 -0
  46. package/dist/constitution/sourceMutation.js +316 -0
  47. package/dist/constitution/structural.js +601 -0
  48. package/dist/core/autoreview.js +27 -3
  49. package/dist/core/dupdetect.js +10 -3
  50. package/dist/core/escalations.js +65 -0
  51. package/dist/core/events.js +61 -0
  52. package/dist/core/externalImports.js +24 -0
  53. package/dist/core/hookpolicy.js +3 -0
  54. package/dist/core/memorylog.js +69 -0
  55. package/dist/core/relativeImports.js +33 -0
  56. package/dist/core/repair.js +71 -0
  57. package/dist/core/reviewqueue.js +11 -0
  58. package/dist/core/stats.js +115 -0
  59. package/dist/extractors/git.js +120 -0
  60. package/dist/extractors/indexer.js +39 -38
  61. package/dist/extractors/nativeTreeSitter.js +108 -0
  62. package/dist/extractors/parse.js +5 -15
  63. package/dist/integrations/claudemd.js +8 -1
  64. package/dist/integrations/gitignore.js +8 -0
  65. package/dist/integrations/providers.js +32 -10
  66. package/dist/integrations/sync.js +16 -1
  67. package/dist/mcp/server.js +317 -1
  68. package/dist/synthesis/synthesize.js +8 -1
  69. package/dist/wiki/graph.js +301 -0
  70. package/dist/wiki/wiki.js +31 -3
  71. package/package.json +5 -1
@@ -22,10 +22,14 @@ import { ensureTeamOverlay } from "../integrations/team.js";
22
22
  import { formatContext, formatStructure } from "../core/format.js";
23
23
  import { compareCandidates } from "../core/compare.js";
24
24
  import { checkConformance } from "../core/conformance.js";
25
+ import { ConstitutionService } from "../constitution/service.js";
26
+ import { G2_RUNBOOK_CATEGORIES } from "../constitution/g2.js";
25
27
  import { renderMarkdown, renderImpact, verdict } from "../core/checkreport.js";
26
28
  import { nowData, wikiStatus, publicHome, readWikiManifestAt } from "../wiki/wiki.js";
27
29
  import { HUNCH_VERSION } from "../core/version.js";
30
+ import { indexRepo } from "../extractors/indexer.js";
28
31
  import { liveForTopic, historyForTopic, rejectedForTopic, captureConflicts } from "../core/topics.js";
32
+ import { pendingEscalations, policyEscalations } from "../core/escalations.js";
29
33
  import { issueCaptureToken as issueToken, consumeCaptureToken as consumeToken } from "../core/capturetoken.js";
30
34
  import { randomUUID } from "node:crypto";
31
35
  const ok = (text) => ({ content: [{ type: "text", text }] });
@@ -338,7 +342,38 @@ export function buildServer(root) {
338
342
  for (const r of roadmap)
339
343
  L.push(` • ${r.title} (${r.id}${r.topic ? `, ${r.topic}` : ""}, since ${r.date})\n ${r.note}`);
340
344
  if (pendingReview > 0)
341
- L.push("", `${pendingReview} auto-drafted proposal(s) awaiting review — \`hunch review\`.`);
345
+ L.push("", `${pendingReview} legacy un-vouched draft(s) — \`hunch adopt-drafts\` auto-trusts them as advisory (new captures land trusted automatically).`);
346
+ const escalations = pendingEscalations(store.json.loadAll("decisions"));
347
+ if (escalations.length) {
348
+ L.push("", `⚖ ${escalations.length} decision(s) need the human's call — ASK inline (never queue): ${escalations.map((e) => e.question).join(" · ")}`);
349
+ }
350
+ return ok(L.join("\n"));
351
+ });
352
+ // -- hunch_escalations (the inline "ask the human" surface) -----------------
353
+ // Captured memory auto-trusts; this returns ONLY what the graph can't resolve
354
+ // itself, framed as questions to raise in conversation: topic conflicts, plus the
355
+ // Constitution's human moments (a candidate awaiting review, a proposed policy
356
+ // whose activation is a human call — §59.5.3). Public store only — same
357
+ // jurisdiction rule as hunch_now (an assistant may paste it). Client-agnostic
358
+ // (con_e04226bd05): no Claude-specific behavior.
359
+ server.registerTool("hunch_escalations", {
360
+ title: "Decisions the human must make now (ask inline, not a queue)",
361
+ description: "The rare decisions the graph cannot resolve on its own — surfaced so you ASK THE USER in the prompt at the moment, then act. Auto-captured memory is trusted automatically and never appears here; this returns topic conflicts (>1 live decision for one topic) and Constitution human moments (candidate policies awaiting review, proposed policies awaiting an activation decision). Normally empty. Raise each question with the user; do NOT decide it for them — an entry is a question, never an approval. Public store only.",
362
+ inputSchema: {},
363
+ }, async () => {
364
+ const items = pendingEscalations(store.json.loadAll("decisions"));
365
+ try {
366
+ items.push(...policyEscalations(new ConstitutionService(store, root).list({ publicOnly: true }).map((p) => ({ ...p, last_action: p.audit.at(-1)?.action ?? null }))));
367
+ }
368
+ catch { /* constitution unavailable — memory escalations still surface */ }
369
+ if (!items.length)
370
+ return ok("✓ Nothing needs a human decision — memory is auto-trusted and self-consistent.");
371
+ const L = [`${items.length} decision(s) need the human's call — ask each inline, don't decide it for them:`, ""];
372
+ for (const e of items) {
373
+ L.push(`⚖ ${e.question}`);
374
+ L.push(` ${e.detail}`);
375
+ L.push(` → ${e.resolution}`, "");
376
+ }
342
377
  return ok(L.join("\n"));
343
378
  });
344
379
  // -- hunch_wiki_status (generated-wiki freshness) ---------------------------
@@ -723,6 +758,191 @@ export function buildServer(root) {
723
758
  return err(`Failed to compare candidates: ${e.message}`);
724
759
  }
725
760
  });
761
+ // -- Hunch Constitution (read-first, agent-neutral Policy IR) ------------
762
+ server.registerTool("hunch_policy_candidates", {
763
+ title: "List Constitution policy candidates",
764
+ description: "List compiled/proposed deterministic Policy IR candidates. Read-only; candidates carry no authority and cannot block. Uses the same Git-native policy store for every MCP client.",
765
+ inputSchema: {
766
+ public_only: z.boolean().optional().describe("Exclude the private overlay from this response."),
767
+ },
768
+ }, async ({ public_only }) => {
769
+ try {
770
+ const service = new ConstitutionService(store, root);
771
+ const candidates = service.list({ publicOnly: public_only }).filter((p) => p.state === "compiled" || p.state === "validating" || p.state === "proposed");
772
+ if (!candidates.length)
773
+ return ok("No Constitution policy candidates.");
774
+ return ok(JSON.stringify(candidates.map((p) => ({ id: p.id, state: p.state, statement: p.statement, proof: p.proof, data_class: p.data_class })), null, 2));
775
+ }
776
+ catch (e) {
777
+ return err(`Failed to list policy candidates: ${e.message}`);
778
+ }
779
+ });
780
+ server.registerTool("hunch_policy_plan", {
781
+ title: "Generate or inspect a Constitution proof plan",
782
+ description: "Return the canonical Git-native ProofPlan for a policy candidate: immutable source/current commits, known-good/bad corpus, mutation operators, expectations, and budgets. Planning executes no replay, model, test, or authority transition.",
783
+ inputSchema: {
784
+ policy_id: z.string().describe("Policy id (pol_*)."),
785
+ public_only: z.boolean().optional().describe("Exclude private-overlay policy and evidence records."),
786
+ },
787
+ }, async ({ policy_id, public_only }) => {
788
+ try {
789
+ return ok(JSON.stringify(new ConstitutionService(store, root).plan(policy_id, { publicOnly: public_only }), null, 2));
790
+ }
791
+ catch (e) {
792
+ return err(`Failed to generate policy proof plan: ${e.message}`);
793
+ }
794
+ });
795
+ server.registerTool("hunch_policy_card", {
796
+ title: "Inspect a Constitution proof card",
797
+ description: "Return the deterministic proof-card view for a policy: exact assertion/scope, raw evidence vector, uncertainty, blocking readiness, authority, limitations, and next actions. Read-only and grants no authority.",
798
+ inputSchema: {
799
+ policy_id: z.string().describe("Policy id (pol_*)."),
800
+ public_only: z.boolean().optional().describe("Exclude private-overlay policy and proof records."),
801
+ },
802
+ }, async ({ policy_id, public_only }) => {
803
+ try {
804
+ return ok(JSON.stringify(new ConstitutionService(store, root).card(policy_id, { publicOnly: public_only }), null, 2));
805
+ }
806
+ catch (e) {
807
+ return err(`Failed to build policy proof card: ${e.message}`);
808
+ }
809
+ });
810
+ server.registerTool("hunch_policy_shadow", {
811
+ title: "Inspect Constitution shadow precision",
812
+ description: "Return the append-only shadow evaluation ledger, current human dispositions, raw precision counts, unknown/error rate, thresholds, and P4-review recommendation for one policy. Read-only: it never records a sample, changes lifecycle, activates, warns, or blocks.",
813
+ inputSchema: {
814
+ policy_id: z.string().describe("Policy id (pol_*)."),
815
+ public_only: z.boolean().optional().describe("Exclude private-overlay shadow records."),
816
+ },
817
+ }, async ({ policy_id, public_only }) => {
818
+ try {
819
+ return ok(JSON.stringify(new ConstitutionService(store, root).shadowReport(policy_id, {}, { publicOnly: public_only }), null, 2));
820
+ }
821
+ catch (e) {
822
+ return err(`Failed to inspect policy shadow precision: ${e.message}`);
823
+ }
824
+ });
825
+ server.registerTool("hunch_policy_proof", {
826
+ title: "Inspect a Constitution policy proof",
827
+ description: "Return the full content-addressed proof artifact for a policy. Read-only; exposes baseline, mutations, proof class, artifact hashes, and limitations without changing authority.",
828
+ inputSchema: {
829
+ policy_id: z.string().describe("Policy id (pol_*)."),
830
+ public_only: z.boolean().optional().describe("Exclude the private overlay from this response."),
831
+ },
832
+ }, async ({ policy_id, public_only }) => {
833
+ try {
834
+ const service = new ConstitutionService(store, root);
835
+ const policy = service.get(policy_id, { publicOnly: public_only });
836
+ if (!policy.proof)
837
+ return ok(`Policy ${policy_id} has no proof yet.`);
838
+ return ok(JSON.stringify(service.proof(policy.proof, { publicOnly: public_only }), null, 2));
839
+ }
840
+ catch (e) {
841
+ return err(`Failed to read policy proof: ${e.message}`);
842
+ }
843
+ });
844
+ server.registerTool("hunch_policy_evaluate", {
845
+ title: "Evaluate Constitution policy",
846
+ description: "Evaluate one or all deterministic Policy IR records and return canonical neutral receipts (satisfied, violated, not_applicable, unknown, error). This is the same evaluator used by CLI and strict CI; models never decide the verdict.",
847
+ inputSchema: {
848
+ policy_id: z.string().optional().describe("Optional policy id; omit for all policies."),
849
+ active_only: z.boolean().optional().describe("Evaluate only active advisory/blocking policies."),
850
+ public_only: z.boolean().optional().describe("Exclude private-overlay policies and graph records."),
851
+ workspace: z.enum(["staged", "working"]).optional().describe("For executable-behavior policies, evaluate the staged index or complete working snapshot in a disposable checkout."),
852
+ commit: z.string().optional().describe("For executable-behavior policies, evaluate an exact commit ref instead of the current committed HEAD."),
853
+ },
854
+ }, async ({ policy_id, active_only, public_only, workspace, commit }) => {
855
+ try {
856
+ if (workspace && commit)
857
+ throw new Error("choose either workspace or commit for executable-behavior evaluation");
858
+ if (commit && !revExists(commit, root))
859
+ throw new Error(`commit ref ${JSON.stringify(commit)} does not resolve`);
860
+ indexRepo(store, root, { churn: false });
861
+ store.reindex();
862
+ const behavior = workspace ? { workspace }
863
+ : commit ? { commit: revParse(commit, root) }
864
+ : undefined;
865
+ const receipts = new ConstitutionService(store, root)
866
+ .evaluate({ id: policy_id, activeOnly: active_only, publicOnly: public_only, behavior })
867
+ .map((r) => r.evaluation);
868
+ return ok(JSON.stringify(receipts, null, 2));
869
+ }
870
+ catch (e) {
871
+ return err(`Failed to evaluate policy: ${e.message}`);
872
+ }
873
+ });
874
+ server.registerTool("hunch_constitution_g2_readiness", {
875
+ title: "Inspect Constitution G2 readiness",
876
+ description: "Return the exact private G2 dogfood evidence packet: human-selected policies, bound proof/corpus/shadow evidence, operational runbook rehearsals, and blockers. Read-only; it never creates evidence, signs off G2, activates policy, warns, or blocks.",
877
+ inputSchema: {},
878
+ }, async () => {
879
+ try {
880
+ return ok(JSON.stringify(new ConstitutionService(store, root).g2Readiness(), null, 2));
881
+ }
882
+ catch (e) {
883
+ return err(`Failed to inspect G2 readiness: ${e.message}`);
884
+ }
885
+ });
886
+ server.registerTool("hunch_constitution_g3_readiness", {
887
+ title: "Inspect Constitution G3 readiness",
888
+ description: "Return the exact private G3 advisory packet: human-selected policies and clients, immutable experiment preregistrations, proof-card comprehension/review measurements, executable adapter conformance, scorecard, and blockers. Read-only; it never records evidence, activates policy, or signs off G3.",
889
+ inputSchema: {},
890
+ }, async () => {
891
+ try {
892
+ return ok(JSON.stringify(new ConstitutionService(store, root).g3Readiness(), null, 2));
893
+ }
894
+ catch (e) {
895
+ return err(`Failed to inspect G3 readiness: ${e.message}`);
896
+ }
897
+ });
898
+ server.registerTool("hunch_constitution_g2_shadow_queue", {
899
+ title: "Review unclassified G2 shadow violations",
900
+ description: "Return a bounded private queue of exact-current-proof G2 shadow violations that still require human classification. Read-only; it never records an observation or disposition, changes lifecycle, grants authority, warns, or blocks.",
901
+ inputSchema: {
902
+ limit: z.number().int().min(1).max(100).optional().describe("Maximum queue items to return (default 20)."),
903
+ },
904
+ }, async ({ limit }) => {
905
+ try {
906
+ return ok(JSON.stringify(new ConstitutionService(store, root).g2ShadowQueue(limit ?? 20), null, 2));
907
+ }
908
+ catch (e) {
909
+ return err(`Failed to inspect the G2 shadow queue: ${e.message}`);
910
+ }
911
+ });
912
+ server.registerTool("hunch_constitution_g2_operational_drill", {
913
+ title: "Execute one exact G2 operational drill",
914
+ description: "Execute the selected private G2 runbook's exact safety regression and return a content-addressed hash-only receipt. Diagnostic only: it writes no rehearsal or shadow evidence, grants no authority, and never signs off G2.",
915
+ inputSchema: {
916
+ category: z.enum(G2_RUNBOOK_CATEGORIES).describe("Exact operational category selected by the current private G2 plan."),
917
+ },
918
+ }, async ({ category }) => {
919
+ try {
920
+ return ok(JSON.stringify(new ConstitutionService(store, root).g2OperationalDrill(category), null, 2));
921
+ }
922
+ catch (e) {
923
+ return err(`Failed to execute the G2 operational drill: ${e.message}`);
924
+ }
925
+ });
926
+ server.registerTool("hunch_constitution_g2_candidates", {
927
+ title: "Review potential G2 dogfood candidates",
928
+ description: "Return a bounded private review packet of exact structural candidates from fix-labeled git history, including the current append-only human selection/rejection when present. Read-only: proposed before/after corpus refs are not replayed evidence, and the tool creates no attestation, policy, proof, corpus, authority, warning, or block.",
929
+ inputSchema: {
930
+ since: z.string().min(1).max(100).optional().describe("Git history window (default 180d)."),
931
+ max_commits: z.number().int().min(1).max(200).optional().describe("Maximum fix-labeled commits to inspect (default 100)."),
932
+ limit: z.number().int().min(1).max(100).optional().describe("Maximum ranked candidates to return (default 30)."),
933
+ },
934
+ }, async ({ since, max_commits, limit }) => {
935
+ try {
936
+ return ok(JSON.stringify(new ConstitutionService(store, root).g2CandidateReview({
937
+ since: since ?? "180d",
938
+ maxCommits: max_commits ?? 100,
939
+ limit: limit ?? 30,
940
+ }), null, 2));
941
+ }
942
+ catch (e) {
943
+ return err(`Failed to inspect G2 candidates: ${e.message}`);
944
+ }
945
+ });
726
946
  // -- hunch_conformance ----------------------------------------------------
727
947
  server.registerTool("hunch_conformance", {
728
948
  title: "Does the code still satisfy the recorded intent?",
@@ -737,6 +957,102 @@ export function buildServer(root) {
737
957
  const head = violations.length ? `⛔ ${violations.length} intent(s) the code no longer satisfies` : "✅ the code satisfies every recorded intent";
738
958
  return ok(`Intent-conformance (${results.length - violations.length}/${results.length} satisfied):\n\n${lines.join("\n")}\n\n${head}`);
739
959
  });
960
+ server.registerTool("hunch_constitution_g2_behavior_candidates", {
961
+ title: "Review executable G2 behavior candidates",
962
+ description: "Derive a bounded private review packet from human-grounded rejected structural proxies and newly added literal node:test cases in their exact fixing commits. Read-only: candidates remain unselected and create no policy, corpus, proof, authority, warning, or block.",
963
+ inputSchema: {
964
+ decision_id: z.string().regex(/^dec_[A-Za-z0-9_-]+$/).optional().describe("Exact current human-confirmed decision to use as the direct behavior grounding batch."),
965
+ since: z.string().min(1).max(100).optional().describe("Git history window (default 180d)."),
966
+ max_commits: z.number().int().min(1).max(200).optional().describe("Maximum fix-labeled commits to inspect (default 100)."),
967
+ limit: z.number().int().min(1).max(100).optional().describe("Maximum behavior candidates to return (default 30)."),
968
+ },
969
+ }, async ({ decision_id, since, max_commits, limit }) => {
970
+ try {
971
+ return ok(JSON.stringify(new ConstitutionService(store, root).g2BehaviorCandidateReview({
972
+ since: since ?? "180d",
973
+ maxCommits: max_commits ?? 100,
974
+ limit: limit ?? 30,
975
+ decisionId: decision_id,
976
+ }), null, 2));
977
+ }
978
+ catch (e) {
979
+ return err(`Failed to inspect G2 behavior candidates: ${e.message}`);
980
+ }
981
+ });
982
+ server.registerTool("hunch_constitution_g2_behavior_replay", {
983
+ title: "Replay one G2 behavior candidate",
984
+ description: "Execute one exact behavior candidate without a shell in disposable known-bad and known-good worktrees, transplanting the hash-bound known-good test file into both. Diagnostic only: writes no Constitution artifact and grants no policy or G2 authority.",
985
+ inputSchema: {
986
+ candidate_id: z.string().regex(/^g2behavior_[a-f0-9]{10}$/),
987
+ review_hash: z.string().regex(/^sha1:[a-f0-9]{40}$/),
988
+ decision_id: z.string().regex(/^dec_[A-Za-z0-9_-]+$/).optional().describe("Exact decision batch used by the reviewed candidate."),
989
+ since: z.string().min(1).max(100).optional().describe("Git history window used by the exact review packet (default 180d)."),
990
+ max_commits: z.number().int().min(1).max(200).optional().describe("Fix-commit bound used by the exact review packet (default 100)."),
991
+ limit: z.number().int().min(1).max(100).optional().describe("Item limit used by the exact review packet (default 30)."),
992
+ timeout_ms: z.number().int().min(1).max(120000).optional().describe("Per-leg execution timeout (default 30000ms)."),
993
+ },
994
+ }, async ({ candidate_id, review_hash, decision_id, since, max_commits, limit, timeout_ms }) => {
995
+ try {
996
+ return ok(JSON.stringify(new ConstitutionService(store, root).g2BehaviorCandidateReplay(candidate_id, review_hash, {
997
+ since: since ?? "180d",
998
+ maxCommits: max_commits ?? 100,
999
+ limit: limit ?? 30,
1000
+ decisionId: decision_id,
1001
+ timeoutMs: timeout_ms ?? 30_000,
1002
+ }), null, 2));
1003
+ }
1004
+ catch (e) {
1005
+ return err(`Failed to replay G2 behavior candidate: ${e.message}`);
1006
+ }
1007
+ });
1008
+ server.registerTool("hunch_constitution_g2_behavior_materialization", {
1009
+ title: "Assess selected G2 behavior materialization",
1010
+ description: "Bind the complete current private behavior review and exact selected attestations, then report whether their durable meanings are expressible by the supported Policy IR. Read-only and fail-closed: unsupported behavior creates no policy, corpus, plan, proof, authority, warning, or block.",
1011
+ inputSchema: {
1012
+ decision_id: z.string().regex(/^dec_[A-Za-z0-9_-]+$/).optional().describe("Exact decision batch to assess."),
1013
+ since: z.string().min(1).max(100).optional().describe("Git history window used by the exact review packet (default 180d)."),
1014
+ max_commits: z.number().int().min(1).max(200).optional().describe("Fix-commit bound used by the exact review packet (default 100)."),
1015
+ limit: z.number().int().min(1).max(100).optional().describe("Item limit used by the exact review packet (default 30)."),
1016
+ },
1017
+ }, async ({ decision_id, since, max_commits, limit }) => {
1018
+ try {
1019
+ return ok(JSON.stringify(new ConstitutionService(store, root).g2BehaviorMaterializationAssessment({
1020
+ since: since ?? "180d",
1021
+ maxCommits: max_commits ?? 100,
1022
+ limit: limit ?? 30,
1023
+ decisionId: decision_id,
1024
+ }), null, 2));
1025
+ }
1026
+ catch (e) {
1027
+ return err(`Failed to assess G2 behavior materialization: ${e.message}`);
1028
+ }
1029
+ });
1030
+ server.registerTool("hunch_constitution_g2_behavior_policy_materialize", {
1031
+ title: "Materialize selected G2 behavior policies",
1032
+ description: "Materialize every current exact selected behavior attestation into a separate private Policy IR v2 proposal, exact corpus and plan, and P3 executable proof. Writes private non-authoritative artifacts only; activation remains a separate explicit human action.",
1033
+ inputSchema: {
1034
+ decision_id: z.string().regex(/^dec_[A-Za-z0-9_-]+$/).optional().describe("Exact decision batch to materialize."),
1035
+ since: z.string().min(1).max(100).optional().describe("Git history window used by the complete exact review packet (default 180d)."),
1036
+ max_commits: z.number().int().min(1).max(200).optional().describe("Fix-commit bound used by the exact review packet (default 100)."),
1037
+ limit: z.number().int().min(1).max(100).optional().describe("Item limit used by the exact review packet (default 30)."),
1038
+ allow_install_scripts: z.array(z.string().min(1).max(214)).max(20).optional().describe("Exact dependency package names allowed to run lifecycle scripts while provisioning snapshots."),
1039
+ dependency_timeout_ms: z.number().int().min(1).max(900000).optional().describe("Timeout for each exact dependency snapshot operation (default 300000ms)."),
1040
+ },
1041
+ }, async ({ decision_id, since, max_commits, limit, allow_install_scripts, dependency_timeout_ms }) => {
1042
+ try {
1043
+ return ok(JSON.stringify(new ConstitutionService(store, root).g2BehaviorPolicyMaterialize({
1044
+ since: since ?? "180d",
1045
+ maxCommits: max_commits ?? 100,
1046
+ limit: limit ?? 30,
1047
+ decisionId: decision_id,
1048
+ allowInstallScripts: allow_install_scripts ?? [],
1049
+ dependencyTimeoutMs: dependency_timeout_ms ?? 300_000,
1050
+ }), null, 2));
1051
+ }
1052
+ catch (e) {
1053
+ return err(`Failed to materialize G2 behavior policies: ${e.message}`);
1054
+ }
1055
+ });
740
1056
  return server;
741
1057
  }
742
1058
  function provLine(record) {
@@ -149,7 +149,14 @@ export async function syncCommit(store, root, sha, opts = {}) {
149
149
  // Auto-synthesized decisions are un-anchored (topic null) — a topic is a human
150
150
  // act, never a machine guess. Preserve one an earlier human capture attached.
151
151
  topic: existing?.topic ?? null,
152
- status: existing?.status === "accepted" ? "accepted" : "proposed",
152
+ // Auto-trust model: captured memory enters the graph LIVE (accepted = in-force
153
+ // advisory), never a `proposed` draft rotting in a review queue. It grounds and
154
+ // ranks immediately but NEVER blocks — the source stays llm_draft, so the veto /
155
+ // strict gates (which key on human_confirmed, not status) treat it as advisory
156
+ // and its tripwires stay unarmed until a human vouches INLINE (dec_a466655539
157
+ // intact). An existing human status (a deliberate `proposed` roadmap entry, or a
158
+ // `superseded` record) is preserved — re-sync never clobbers a human's intent.
159
+ status: existing?.status ?? "accepted",
153
160
  context: draft.context + constraintNote,
154
161
  decision: draft.decision,
155
162
  consequences: draft.consequences,