@davesheffer/hunch 1.31.0 → 1.32.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.
- package/README.md +3 -6
- package/dist/cli/automaticReviewMemory.d.ts +13 -0
- package/dist/cli/dna.d.ts +2 -0
- package/dist/cli/index.d.ts +16 -0
- package/dist/cli/index.js +602 -43
- package/dist/cli/integrations.d.ts +2 -0
- package/dist/cli/integrations.js +5 -2
- package/dist/cli/invocation.d.ts +35 -0
- package/dist/cli/preflight.d.ts +1 -0
- package/dist/cli/reviewMemory.d.ts +4 -0
- package/dist/cli/reviewMemoryProvider.d.ts +14 -0
- package/dist/cli/serve.d.ts +2 -0
- package/dist/cli/taskReport.d.ts +6 -0
- package/dist/cli/taskReport.js +124 -0
- package/dist/cli/update.d.ts +14 -0
- package/dist/client/state.d.ts +248 -0
- package/dist/client/state.js +2 -0
- package/dist/constitution/adapters.d.ts +29 -0
- package/dist/constitution/behaviorAttestationBinding.d.ts +3 -0
- package/dist/constitution/behaviorEvaluator.d.ts +8 -0
- package/dist/constitution/behaviorProof.d.ts +9 -0
- package/dist/constitution/behaviorWorkspace.d.ts +25 -0
- package/dist/constitution/bootstrap.d.ts +30 -0
- package/dist/constitution/canonical.d.ts +15 -0
- package/dist/constitution/card.d.ts +58 -0
- package/dist/constitution/compiler.d.ts +52 -0
- package/dist/constitution/composition.d.ts +10 -0
- package/dist/constitution/corpus.d.ts +7 -0
- package/dist/constitution/correctionPolicyMaterializer.d.ts +57 -0
- package/dist/constitution/delta.d.ts +4 -0
- package/dist/constitution/disposition.d.ts +20 -0
- package/dist/constitution/evaluator.d.ts +47 -0
- package/dist/constitution/experiment.d.ts +466 -0
- package/dist/constitution/experimentRunner.d.ts +7 -0
- package/dist/constitution/g2.d.ts +209 -0
- package/dist/constitution/g2BehaviorAttestation.d.ts +45 -0
- package/dist/constitution/g2BehaviorCandidates.d.ts +123 -0
- package/dist/constitution/g2BehaviorDependencies.d.ts +83 -0
- package/dist/constitution/g2BehaviorMaterialization.d.ts +77 -0
- package/dist/constitution/g2BehaviorPolicyMaterializer.d.ts +48 -0
- package/dist/constitution/g2CandidateAttestation.d.ts +43 -0
- package/dist/constitution/g2Candidates.d.ts +80 -0
- package/dist/constitution/g2Drills.d.ts +33 -0
- package/dist/constitution/g3.d.ts +311 -0
- package/dist/constitution/g3Conformance.d.ts +33 -0
- package/dist/constitution/lifecycle.d.ts +25 -0
- package/dist/constitution/mutation.d.ts +15 -0
- package/dist/constitution/nodeTestEvidence.d.ts +13 -0
- package/dist/constitution/plan.d.ts +18 -0
- package/dist/constitution/policyRuntime.d.ts +5 -0
- package/dist/constitution/proof.d.ts +11 -0
- package/dist/constitution/repairPolicies.d.ts +34 -0
- package/dist/constitution/replacementFreeGit.d.ts +14 -0
- package/dist/constitution/replay.d.ts +40 -0
- package/dist/constitution/replayCache.d.ts +14 -0
- package/dist/constitution/replayWorker.d.ts +1 -0
- package/dist/constitution/repository.d.ts +129 -0
- package/dist/constitution/safeCheckout.d.ts +9 -0
- package/dist/constitution/schema.d.ts +1763 -0
- package/dist/constitution/scorecard.d.ts +219 -0
- package/dist/constitution/service.d.ts +398 -0
- package/dist/constitution/shadow.d.ts +54 -0
- package/dist/constitution/sourceMutation.d.ts +15 -0
- package/dist/constitution/staticGraphBaseline.d.ts +13 -0
- package/dist/constitution/structural.d.ts +64 -0
- package/dist/core/agenthook.d.ts +63 -0
- package/dist/core/agenthook.js +1 -0
- package/dist/core/automaticReviewMemory.d.ts +60 -0
- package/dist/core/autoreview.d.ts +66 -0
- package/dist/core/canonicalOrder.d.ts +3 -0
- package/dist/core/capturetoken.d.ts +19 -0
- package/dist/core/changeIdentity.d.ts +22 -0
- package/dist/core/changeProof.d.ts +14 -0
- package/dist/core/checkreport.d.ts +140 -0
- package/dist/core/commitrepair.d.ts +171 -0
- package/dist/core/commitrepair.js +238 -0
- package/dist/core/compare.d.ts +21 -0
- package/dist/core/config.d.ts +20 -0
- package/dist/core/conformance.d.ts +35 -0
- package/dist/core/constraintmatch.d.ts +54 -0
- package/dist/core/correction.d.ts +42 -0
- package/dist/core/correctionStage.d.ts +224 -0
- package/dist/core/declarationClusters.d.ts +149 -0
- package/dist/core/delivery.d.ts +110 -0
- package/dist/core/docanchors.d.ts +32 -0
- package/dist/core/docscan.d.ts +26 -0
- package/dist/core/drift.d.ts +13 -0
- package/dist/core/drift.js +31 -1
- package/dist/core/dupdetect.d.ts +43 -0
- package/dist/core/escalations.d.ts +129 -0
- package/dist/core/escalations.js +165 -0
- package/dist/core/events.d.ts +29 -0
- package/dist/core/evidenceMap.d.ts +164 -0
- package/dist/core/externalImports.d.ts +8 -0
- package/dist/core/format.d.ts +13 -0
- package/dist/core/glob.d.ts +9 -0
- package/dist/core/groundingLag.d.ts +84 -0
- package/dist/core/groundingLag.js +16 -2
- package/dist/core/groundingMerge.d.ts +15 -0
- package/dist/core/groundingMerge.js +95 -0
- package/dist/core/hookcache.d.ts +10 -0
- package/dist/core/hookpolicy.d.ts +47 -0
- package/dist/core/ids.d.ts +36 -0
- package/dist/core/importReview.d.ts +30 -0
- package/dist/core/io.d.ts +23 -0
- package/dist/core/jsonc.d.ts +4 -0
- package/dist/core/landscapeAdoption.d.ts +66 -0
- package/dist/core/landscapeDelivery.d.ts +76 -0
- package/dist/core/memorylog.d.ts +37 -0
- package/dist/core/migrate.d.ts +28 -0
- package/dist/core/outcomeExperience.d.ts +89 -0
- package/dist/core/overlaySafety.d.ts +24 -0
- package/dist/core/overlaySafety.js +7 -1
- package/dist/core/paths.d.ts +31 -0
- package/dist/core/pipeline.d.ts +289 -0
- package/dist/core/premises.d.ts +43 -0
- package/dist/core/provenance.d.ts +21 -0
- package/dist/core/publication.d.ts +54 -0
- package/dist/core/refrepair.d.ts +24 -0
- package/dist/core/refrepair.js +1 -1
- package/dist/core/relativeImports.d.ts +11 -0
- package/dist/core/repair.d.ts +44 -0
- package/dist/core/repairqueue.d.ts +40 -0
- package/dist/core/repairqueue.js +133 -0
- package/dist/core/reviewMemory.d.ts +40 -0
- package/dist/core/reviewqueue.d.ts +54 -0
- package/dist/core/safeRepoFile.d.ts +20 -0
- package/dist/core/served.d.ts +57 -0
- package/dist/core/served.js +14 -0
- package/dist/core/stateContract.d.ts +979 -0
- package/dist/core/stateContract.js +87 -4
- package/dist/core/stateDelivery.d.ts +78 -0
- package/dist/core/stateRecords.d.ts +383 -0
- package/dist/core/stateRecords.js +16 -1
- package/dist/core/stats.d.ts +88 -0
- package/dist/core/strictgate.d.ts +33 -0
- package/dist/core/taskReport.d.ts +226 -0
- package/dist/core/taskReport.js +514 -0
- package/dist/core/taskReportCapture.d.ts +8 -0
- package/dist/core/taskReportCapture.js +36 -0
- package/dist/core/taskReportEvidence.d.ts +26 -0
- package/dist/core/taskReportEvidence.js +268 -0
- package/dist/core/taskReportHook.d.ts +20 -0
- package/dist/core/taskReportHook.js +76 -0
- package/dist/core/taskReportPaths.d.ts +3 -0
- package/dist/core/taskReportPaths.js +23 -0
- package/dist/core/taskReportPublic.d.ts +31 -0
- package/dist/core/taskReportPublic.js +45 -0
- package/dist/core/taskReportRender.d.ts +6 -0
- package/dist/core/taskReportRender.js +97 -0
- package/dist/core/topics.d.ts +73 -0
- package/dist/core/types.d.ts +1239 -0
- package/dist/core/version.d.ts +10 -0
- package/dist/eval/guards.d.ts +45 -0
- package/dist/eval/harness.d.ts +58 -0
- package/dist/extractors/adrImport.d.ts +59 -0
- package/dist/extractors/comments.d.ts +7 -0
- package/dist/extractors/correctionSources.d.ts +11 -0
- package/dist/extractors/diff.d.ts +40 -0
- package/dist/extractors/git.d.ts +304 -0
- package/dist/extractors/git.js +208 -20
- package/dist/extractors/helm.d.ts +31 -0
- package/dist/extractors/indexer.d.ts +55 -0
- package/dist/extractors/landscapeDiscovery.d.ts +41 -0
- package/dist/extractors/languages.d.ts +77 -0
- package/dist/extractors/nativeTreeSitter.d.ts +16 -0
- package/dist/extractors/parse.d.ts +54 -0
- package/dist/extractors/php.d.ts +26 -0
- package/dist/extractors/repoSource.d.ts +53 -0
- package/dist/extractors/testreport.d.ts +36 -0
- package/dist/integrations/ciAction.d.ts +8 -0
- package/dist/integrations/claudeConfig.d.ts +44 -0
- package/dist/integrations/claudemd.d.ts +13 -0
- package/dist/integrations/claudemd.js +11 -2
- package/dist/integrations/gitignore.d.ts +16 -0
- package/dist/integrations/gitignore.js +7 -0
- package/dist/integrations/health.d.ts +74 -0
- package/dist/integrations/hooks.d.ts +41 -0
- package/dist/integrations/hooks.js +92 -66
- package/dist/integrations/madrExport.d.ts +39 -0
- package/dist/integrations/madrManifest.d.ts +69 -0
- package/dist/integrations/mergeDriver.d.ts +3 -0
- package/dist/integrations/mergeDriver.js +25 -8
- package/dist/integrations/probe.d.ts +4 -0
- package/dist/integrations/providers.d.ts +103 -0
- package/dist/integrations/scaffold.d.ts +29 -0
- package/dist/integrations/sync.d.ts +30 -0
- package/dist/integrations/sync.js +3 -2
- package/dist/integrations/team.d.ts +70 -0
- package/dist/integrations/worktree.d.ts +8 -0
- package/dist/mcp/roots.d.ts +16 -0
- package/dist/mcp/server.d.ts +36 -0
- package/dist/mcp/server.js +114 -25
- package/dist/mcp/taskReportTools.d.ts +3 -0
- package/dist/mcp/taskReportTools.js +106 -0
- package/dist/serve/app.d.ts +36 -0
- package/dist/serve/app.js +20 -0
- package/dist/serve/config.d.ts +100 -0
- package/dist/serve/writelock.d.ts +22 -0
- package/dist/store/changeLedger.d.ts +132 -0
- package/dist/store/changeLedger.js +40 -9
- package/dist/store/compact.d.ts +33 -0
- package/dist/store/db.d.ts +9 -0
- package/dist/store/embedder.d.ts +32 -0
- package/dist/store/hunchStore.d.ts +624 -0
- package/dist/store/hunchStore.js +13 -5
- package/dist/store/jsonStore.d.ts +125 -0
- package/dist/store/jsonStore.js +15 -0
- package/dist/store/merge.d.ts +39 -0
- package/dist/store/privateMigrate.d.ts +24 -0
- package/dist/store/replay.d.ts +56 -0
- package/dist/store/schema.d.ts +17 -0
- package/dist/store/stateBinding.d.ts +145 -0
- package/dist/store/stateBinding.js +110 -15
- package/dist/store/stateCapture.d.ts +15 -0
- package/dist/store/stateCapture.js +145 -0
- package/dist/synthesis/cliAdapter.d.ts +22 -0
- package/dist/synthesis/initiator.d.ts +13 -0
- package/dist/synthesis/provider.d.ts +307 -0
- package/dist/synthesis/synthesize.d.ts +117 -0
- package/dist/synthesis/tripwires.d.ts +9 -0
- package/dist/taskReports.d.ts +76 -0
- package/dist/taskReports.js +67 -0
- package/dist/wiki/adopt.d.ts +22 -0
- package/dist/wiki/graph.d.ts +87 -0
- package/dist/wiki/wiki.d.ts +242 -0
- package/package.json +6 -5
- package/server.json +2 -2
|
@@ -29,17 +29,22 @@ import { z } from "zod";
|
|
|
29
29
|
import { compareCodeUnits } from "./canonicalOrder.js";
|
|
30
30
|
import { DELIVERY_PROFILES } from "./delivery.js";
|
|
31
31
|
import { isHumanConfirmed as sourceIsHumanConfirmed } from "./strictgate.js";
|
|
32
|
-
import { ScopeSchema, scopePath, DependencyRefSchema, ExternalRefSchema, RECEIPT_SCHEMA_VERSION, COMMITMENT_SCHEMA_VERSION, DERIVED_SCHEMA_VERSION, ENTITY_SCHEMA_VERSION, RELATIONSHIP_SCHEMA_VERSION, } from "./stateRecords.js";
|
|
32
|
+
import { ScopeSchema, scopePath, externalKey, DependencyRefSchema, ExternalRefSchema, RECEIPT_SCHEMA_VERSION, COMMITMENT_SCHEMA_VERSION, DERIVED_SCHEMA_VERSION, ENTITY_SCHEMA_VERSION, RELATIONSHIP_SCHEMA_VERSION, } from "./stateRecords.js";
|
|
33
33
|
export * from "./stateRecords.js";
|
|
34
34
|
export const STATE_CONTRACT_VERSION = "nuryel.state/1";
|
|
35
35
|
export const STATE_READ_VERSION = "nuryel.state.read/1";
|
|
36
36
|
export const STATE_WRITE_VERSION = "nuryel.state.write/1";
|
|
37
37
|
export const STATE_SUBSCRIBE_VERSION = "nuryel.state.subscribe/1";
|
|
38
38
|
export const STATE_RECORDS_VERSION = "nuryel.state.records/1";
|
|
39
|
+
export const STATE_CAPTURE_VERSION = "nuryel.state.capture/1";
|
|
40
|
+
export const STATE_CAPTURE_BATCH_VERSION = "nuryel.state.capture-batch/1";
|
|
41
|
+
export const STATE_OBSERVATION_LINKS_VERSION = "nuryel.observation-links/1";
|
|
42
|
+
export const STATE_OBSERVATION_REVIEW_VERSION = "nuryel.observation-review/1";
|
|
43
|
+
export const STATE_OBSERVATION_PAGES_VERSION = "nuryel.observation-pages/1";
|
|
39
44
|
/** Capabilities a server advertises; a client that needs one the server lacks gets a typed
|
|
40
45
|
* `unsupported`, never a compatible-looking degraded answer. */
|
|
41
46
|
export const STATE_CAPABILITIES = [
|
|
42
|
-
STATE_READ_VERSION, STATE_WRITE_VERSION, STATE_SUBSCRIBE_VERSION, STATE_RECORDS_VERSION,
|
|
47
|
+
STATE_READ_VERSION, STATE_WRITE_VERSION, STATE_SUBSCRIBE_VERSION, STATE_RECORDS_VERSION, STATE_CAPTURE_VERSION, STATE_CAPTURE_BATCH_VERSION, STATE_OBSERVATION_LINKS_VERSION, STATE_OBSERVATION_REVIEW_VERSION, STATE_OBSERVATION_PAGES_VERSION,
|
|
43
48
|
RECEIPT_SCHEMA_VERSION, COMMITMENT_SCHEMA_VERSION, DERIVED_SCHEMA_VERSION, ENTITY_SCHEMA_VERSION, RELATIONSHIP_SCHEMA_VERSION,
|
|
44
49
|
];
|
|
45
50
|
const SHA256 = /^sha256:[a-f0-9]{64}$/;
|
|
@@ -55,12 +60,52 @@ export const PrincipalSchema = z.object({
|
|
|
55
60
|
display: z.string().max(256).optional(),
|
|
56
61
|
grants: z.array(ScopeSchema).min(1).max(64),
|
|
57
62
|
}).strict();
|
|
63
|
+
/** One relevant assertion, never a whole conversation. Source text is transient input:
|
|
64
|
+
* only its exact supporting excerpt and a hashed external pointer may reach the store. */
|
|
65
|
+
export const CaptureRequestSchema = z.object({
|
|
66
|
+
schema: z.literal(STATE_CAPTURE_VERSION),
|
|
67
|
+
principal: PrincipalSchema,
|
|
68
|
+
scope: ScopeSchema,
|
|
69
|
+
subject: z.string().min(1).max(512),
|
|
70
|
+
statement: z.string().trim().min(1).max(1200),
|
|
71
|
+
relevance: z.object({
|
|
72
|
+
use: z.enum(["decision", "constraint", "preference", "operational_fact", "ongoing_issue"]),
|
|
73
|
+
reason: z.string().trim().min(1).max(600),
|
|
74
|
+
}).strict(),
|
|
75
|
+
evidence: z.array(z.object({
|
|
76
|
+
ref: ExternalRefSchema,
|
|
77
|
+
source_text: z.string().min(1).max(64000),
|
|
78
|
+
excerpt: z.string().trim().min(1).max(1200),
|
|
79
|
+
}).strict()).min(1).max(8),
|
|
80
|
+
}).strict();
|
|
81
|
+
/** Sources cross the transport once; assertions name only their supporting excerpts. */
|
|
82
|
+
export const CaptureBatchRequestSchema = z.object({
|
|
83
|
+
schema: z.literal(STATE_CAPTURE_BATCH_VERSION), principal: PrincipalSchema, scope: ScopeSchema,
|
|
84
|
+
sources: z.array(CaptureRequestSchema.shape.evidence.element.omit({ excerpt: true })).min(1).max(8),
|
|
85
|
+
observations: z.array(CaptureRequestSchema.pick({ subject: true, statement: true, relevance: true }).extend({
|
|
86
|
+
evidence: z.array(z.object({ source: z.number().int().min(0).max(7), excerpt: z.string().trim().min(1).max(1200) }).strict()).min(1).max(8),
|
|
87
|
+
})).min(0).max(32),
|
|
88
|
+
reviews: z.array(z.object({
|
|
89
|
+
record_id: z.string().regex(/^nds_[a-f0-9]{24}$/), expected_hash: z.string().regex(SHA256),
|
|
90
|
+
reason: z.string().trim().min(1).max(600),
|
|
91
|
+
evidence: z.array(z.object({ source: z.number().int().min(0).max(7), excerpt: z.string().trim().min(1).max(1200) }).strict()).min(1).max(8),
|
|
92
|
+
}).strict()).min(1).max(32).optional(),
|
|
93
|
+
}).strict();
|
|
94
|
+
export const CAPTURE_TRANSFORM = "agent-capture/1:";
|
|
95
|
+
export const normalizeAssertion = (text) => text.normalize("NFC").replace(/\r\n?/g, "\n").trim();
|
|
96
|
+
export function captureTransform(scope, subject, statement, evidence) {
|
|
97
|
+
const identities = [...new Set(evidence.map(e => stateHash({ source: e.source, excerpt: normalizeAssertion(e.excerpt) })))].sort();
|
|
98
|
+
return CAPTURE_TRANSFORM + stateHash({ scope, subject, statement: normalizeAssertion(statement), evidence: identities }).slice(7);
|
|
99
|
+
}
|
|
58
100
|
export const STATE_FACETS = ["decisions", "constraints", "bugs", "findings", "receipts", "commitments", "derived", "entities", "relationships"];
|
|
59
101
|
// ---- verbs ------------------------------------------------------------------------------
|
|
60
102
|
/** Union read: the partitions a principal wants in ONE answer. `scope` stays required (it is the
|
|
61
103
|
* primary partition; its envelope and receipt lead the response). An entry the principal is not
|
|
62
104
|
* granted is NAMED in `denied_scopes` — it never refuses the whole call, and is never described. */
|
|
63
105
|
export const ReadScopesSchema = z.array(ScopeSchema).min(1).max(64);
|
|
106
|
+
export const ObservationCursorSchema = z.object({
|
|
107
|
+
snapshot_hash: z.string().regex(SHA256), offset: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
108
|
+
}).strict();
|
|
64
109
|
export const ReadRequestSchema = z.object({
|
|
65
110
|
schema: z.literal(STATE_READ_VERSION),
|
|
66
111
|
principal: PrincipalSchema,
|
|
@@ -71,6 +116,8 @@ export const ReadRequestSchema = z.object({
|
|
|
71
116
|
profile: z.enum(DELIVERY_PROFILES).optional(),
|
|
72
117
|
budget_tokens: z.number().int().min(200).max(200_000).optional(),
|
|
73
118
|
facets: z.array(z.enum(STATE_FACETS)).max(STATE_FACETS.length).optional(),
|
|
119
|
+
/** Explicit single-partition pagination; default subject reads keep their existing bound. */
|
|
120
|
+
observed_page: z.object({ cursor: ObservationCursorSchema.optional() }).strict().optional(),
|
|
74
121
|
}).strict();
|
|
75
122
|
const StateRefSchema = z.object({
|
|
76
123
|
facet: z.enum(STATE_FACETS),
|
|
@@ -85,6 +132,11 @@ export const StateOfRecordSchema = z.object({
|
|
|
85
132
|
current: z.array(StateRefSchema).max(256),
|
|
86
133
|
in_force: z.array(StateRefSchema).max(256),
|
|
87
134
|
done: z.array(StateRefSchema).max(256),
|
|
135
|
+
/** Source-backed observations, not a claim of currentness. Additive; absent on old hosts. */
|
|
136
|
+
observed: z.array(StateRefSchema).max(64).optional(),
|
|
137
|
+
observed_truncated: z.boolean().optional(),
|
|
138
|
+
observed_page: z.object({ snapshot_hash: z.string().regex(SHA256), total: z.number().int().nonnegative(), next_cursor: ObservationCursorSchema.nullable() }).strict().optional(),
|
|
139
|
+
relationships_truncated: z.boolean().optional(),
|
|
88
140
|
depends_on: z.array(DependencyRefSchema).max(1024),
|
|
89
141
|
invalidated_by: z.array(z.string().max(512)).max(256),
|
|
90
142
|
}).strict();
|
|
@@ -131,6 +183,17 @@ export const WriteResultSchema = z.object({
|
|
|
131
183
|
* what landed without a second lookup. Additive. */
|
|
132
184
|
record: z.record(z.string(), z.unknown()).optional(),
|
|
133
185
|
}).strict();
|
|
186
|
+
export const CaptureBatchResultSchema = z.object({
|
|
187
|
+
schema: z.literal(STATE_CAPTURE_BATCH_VERSION),
|
|
188
|
+
results: z.array(z.discriminatedUnion("status", [
|
|
189
|
+
z.object({ index: z.number().int(), status: z.literal("saved"), result: WriteResultSchema }).strict(),
|
|
190
|
+
z.object({ index: z.number().int(), status: z.literal("refused"), code: z.string(), message: z.string() }).strict(),
|
|
191
|
+
])).max(32),
|
|
192
|
+
reviews: z.array(z.discriminatedUnion("status", [
|
|
193
|
+
z.object({ index: z.number().int(), status: z.literal("saved"), result: WriteResultSchema }).strict(),
|
|
194
|
+
z.object({ index: z.number().int(), status: z.literal("refused"), code: z.string(), message: z.string() }).strict(),
|
|
195
|
+
])).max(32).optional(),
|
|
196
|
+
}).strict();
|
|
134
197
|
export const SubscribeRequestSchema = z.object({
|
|
135
198
|
schema: z.literal(STATE_SUBSCRIBE_VERSION),
|
|
136
199
|
principal: PrincipalSchema,
|
|
@@ -224,6 +287,11 @@ export function commitmentId(c) {
|
|
|
224
287
|
return idFrom("ncm", { scope: c.scope, subject: c.subject, title: c.title.trim(), owner: c.owner, due: c.due });
|
|
225
288
|
}
|
|
226
289
|
export function derivedId(d) {
|
|
290
|
+
// Capture's reserved transform includes assertion/evidence identity, independent of
|
|
291
|
+
// read time and unrelated source edits. Ordinary summary identity is unchanged.
|
|
292
|
+
if (/^agent-capture\/1:[a-f0-9]{64}$/.test(d.transform_version)) {
|
|
293
|
+
return idFrom("nds", { scope: d.scope, subject: d.subject, transform_version: d.transform_version });
|
|
294
|
+
}
|
|
227
295
|
return idFrom("nds", { scope: d.scope, subject: d.subject, transform_version: d.transform_version, dependencies: d.dependencies.map((dep) => stateHash(dep)).sort(compareCodeUnits) });
|
|
228
296
|
}
|
|
229
297
|
// ---- invariants --------------------------------------------------------------------------
|
|
@@ -237,7 +305,7 @@ export const STATE_INVARIANTS = [
|
|
|
237
305
|
{ id: "derived-state-carries-dependencies", statement: "A derived statement without dependencies cannot be invalidated and is therefore not state." },
|
|
238
306
|
{ id: "one-entity-per-external-ref", statement: "One external record is one entity in a partition: a second active entity carrying an external key an incumbent already carries is refused with the incumbent named, and a subject written as that record's external key is refused with the entity's id named. Identity is explicit refs, never similarity; merge is explicit — a retired entity names the survivor in `merged_into`, the ledger holds the `retired` event, nothing under the old id is rewritten and reads resolve to the survivor — and split is the explicit reverse; never a silent rewrite." },
|
|
239
307
|
{ id: "human-correction-outranks-agent-writes", statement: "A record a human confirmed is never overwritten or superseded by an agent or service principal: the agent may replay it, write derived state back stale with the external cause that moved, or close a commitment with a receipt on record. Changing what the human said takes a human." },
|
|
240
|
-
{ id: "derived-state-writer-owns-currentness", statement: "No source writes the drawer. The writer of a derived statement owns keeping its dependencies true: re-validate them on a schedule or on a source event, and write the statement back stale with the moved pointer as cause when one no longer holds.
|
|
308
|
+
{ id: "derived-state-writer-owns-currentness", statement: "No source writes the drawer. The writer of a current derived statement owns keeping its dependencies true: re-validate them on a schedule or on a source event, and write the statement back stale with the moved pointer as cause when one no longer holds. Without this duty an agent may capture source-backed observations only as unknown; observations never assert currentness." },
|
|
241
309
|
];
|
|
242
310
|
const grantKey = (scope) => scopePath(scope);
|
|
243
311
|
/** The memory supply chain's top tier: a record whose provenance a human signed. Same tier rule
|
|
@@ -252,7 +320,7 @@ export function assertReadWithinGrants(principal, response) {
|
|
|
252
320
|
const granted = new Set(principal.grants.map(grantKey));
|
|
253
321
|
if (!granted.has(grantKey(response.scope)))
|
|
254
322
|
throw new Error(`read response scope ${grantKey(response.scope)} is outside the principal's grants`);
|
|
255
|
-
const refs = response.state_of_record ? [...response.state_of_record.current, ...response.state_of_record.in_force, ...response.state_of_record.done] : [];
|
|
323
|
+
const refs = response.state_of_record ? [...response.state_of_record.current, ...response.state_of_record.in_force, ...response.state_of_record.done, ...(response.state_of_record.observed ?? [])] : [];
|
|
256
324
|
for (const ref of refs) {
|
|
257
325
|
if (!granted.has(grantKey(ref.scope)))
|
|
258
326
|
throw new Error(`state ref ${ref.id} in scope ${grantKey(ref.scope)} leaked outside the principal's grants`);
|
|
@@ -289,6 +357,21 @@ export function assertDerivedState(d) {
|
|
|
289
357
|
throw new Error("derived state without dependencies is not state");
|
|
290
358
|
if (stateHash(d.content) !== d.content_hash)
|
|
291
359
|
throw new Error("derived state content hash does not match its content");
|
|
360
|
+
if (d.transform_version.startsWith(CAPTURE_TRANSFORM)) {
|
|
361
|
+
const content = z.object({
|
|
362
|
+
schema: z.literal("nuryel.observation-content/1"),
|
|
363
|
+
statement: CaptureRequestSchema.shape.statement, relevance: CaptureRequestSchema.shape.relevance,
|
|
364
|
+
evidence: z.array(z.object({ source: z.string(), excerpt: z.string().min(1).max(1200) }).strict()).min(1).max(8),
|
|
365
|
+
captured_by: PrincipalSchema.shape.id,
|
|
366
|
+
}).strict().parse(JSON.parse(d.content));
|
|
367
|
+
if (d.state === "current")
|
|
368
|
+
throw new Error("capture observations cannot assert currentness; publish a separately revalidated summary");
|
|
369
|
+
if (captureTransform(d.scope, d.subject, content.statement, content.evidence) !== d.transform_version)
|
|
370
|
+
throw new Error("capture identity does not match its assertion and evidence");
|
|
371
|
+
const pointers = new Set(d.dependencies.filter(dep => dep.kind === "external").map(dep => externalKey(dep.ref)));
|
|
372
|
+
if (content.evidence.some(e => !pointers.has(e.source)))
|
|
373
|
+
throw new Error("capture evidence lacks its external dependency");
|
|
374
|
+
}
|
|
292
375
|
}
|
|
293
376
|
/** Subscribe streams are strictly ordered per scope; a gap or regression means the caller must
|
|
294
377
|
* resynchronize instead of trusting what it holds. */
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nuryel.state/1 — search and delivery of the five state kinds (receipts, commitments,
|
|
3
|
+
* derived, entities, relationships). Registered in 1.25 as store kinds, they were stored and
|
|
4
|
+
* counted but neither indexed nor delivered: `hunch_query("customer:Site:7")` could not surface
|
|
5
|
+
* a current summary, an open commitment or a verified receipt, and `hunch_context` had no
|
|
6
|
+
* "State" section. This module is the single place that says, per kind:
|
|
7
|
+
*
|
|
8
|
+
* - what text goes into the `search` FTS row (subject + content/title + actor + status, so a
|
|
9
|
+
* subject id and a human phrase both hit),
|
|
10
|
+
* - whether a record is LIVE (current / in_force / verified…) or HISTORY (superseded, done,
|
|
11
|
+
* cancelled, failed, retired) — history stays indexed and findable, it only ranks below,
|
|
12
|
+
* - the one-line render every reader gets (`[commitment/in_force] customer:Site:7 — …`),
|
|
13
|
+
* - the bounded, deterministically ordered "State" supplements for a context brief.
|
|
14
|
+
*
|
|
15
|
+
* Pure functions over records; no store or SQLite dependency, so the CLI, the MCP server and
|
|
16
|
+
* the store's own reindex/rank paths cannot drift from each other.
|
|
17
|
+
*/
|
|
18
|
+
import type { ActionReceipt, Commitment, DerivedState, ExternalEntity, StateRelationship } from "./stateRecords.js";
|
|
19
|
+
import type { DeliverySupplement } from "./delivery.js";
|
|
20
|
+
export declare const STATE_KINDS: readonly ["receipts", "commitments", "derived", "entities", "relationships"];
|
|
21
|
+
export type StateKind = (typeof STATE_KINDS)[number];
|
|
22
|
+
export declare function isStateKind(kind: string): kind is StateKind;
|
|
23
|
+
export type StateRecord = ActionReceipt | Commitment | DerivedState | ExternalEntity | StateRelationship;
|
|
24
|
+
export interface StateLiveness {
|
|
25
|
+
/** The contract's own word for the record's standing: current, in_force, verified, done, superseded … */
|
|
26
|
+
label: string;
|
|
27
|
+
/** True when the record is the state of record NOW; false for history (still indexed, ranked below). */
|
|
28
|
+
live: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** Liveness per kind, mirroring readState's state_of_record predicates exactly
|
|
31
|
+
* (derived `current` with an open window; commitment open/waiting with an open window;
|
|
32
|
+
* receipt succeeded/verified; entity active; a relationship is always current). */
|
|
33
|
+
export declare function stateLiveness(kind: StateKind, record: StateRecord): StateLiveness;
|
|
34
|
+
/** The subject key a reader would type: the commitment/derived subject, the receipt's target
|
|
35
|
+
* object (`event:10042`), the entity id, or the relationship's `from` endpoint. */
|
|
36
|
+
export declare function stateSubject(kind: StateKind, record: StateRecord): string;
|
|
37
|
+
/** The instant that orders "latest first": computed_at, valid_from, verified_at ?? occurred_at,
|
|
38
|
+
* updated_at. Relationships carry no clock and sort last among equals. */
|
|
39
|
+
export declare function stateObservedAt(kind: StateKind, record: StateRecord): string;
|
|
40
|
+
/** The FTS document for a state record: title = the subject key (so an id query hits the
|
|
41
|
+
* title column, which the snippet and LIKE fallback both prefer), body = the human words plus
|
|
42
|
+
* the actor/owner, the status label and the dates. Every reader's query — a subject id, a
|
|
43
|
+
* phrase from a summary, an action kind, a principal — lands on one of these. */
|
|
44
|
+
export declare function stateSearchDoc(kind: StateKind, record: StateRecord): {
|
|
45
|
+
title: string;
|
|
46
|
+
body: string;
|
|
47
|
+
};
|
|
48
|
+
/** The one-line render shared by hunch_query, `hunch query` and the context "State" section:
|
|
49
|
+
* [commitment/in_force] customer:Site:7 — "send report" due 2026-09-11 (owner sofia)
|
|
50
|
+
* [derived/current] customer:Site:7 — <first 120 chars of the summary>
|
|
51
|
+
* [receipt/verified] event:10042 — events_add_actions by sofia@david 2026-09-08 */
|
|
52
|
+
export declare function renderStateLine(kind: StateKind, record: StateRecord): string;
|
|
53
|
+
/** One ranked state hit, as the store's stateSlice() returns it. `score` is the search
|
|
54
|
+
* score (bm25: lower is better; 0 for the LIKE fallback and exact-subject matches). */
|
|
55
|
+
export interface StateHit<K extends StateKind = StateKind> {
|
|
56
|
+
kind: K;
|
|
57
|
+
record: StateRecord;
|
|
58
|
+
score: number;
|
|
59
|
+
}
|
|
60
|
+
/** Bounded caps for the context "State" section: current derived, in-force commitments,
|
|
61
|
+
* latest receipts. Deliberately small — a brief, not a dump; `nuryel_read` is the full view. */
|
|
62
|
+
export declare const STATE_SLICE_CAPS: {
|
|
63
|
+
readonly derived: 3;
|
|
64
|
+
readonly commitments: 5;
|
|
65
|
+
readonly receipts: 3;
|
|
66
|
+
};
|
|
67
|
+
export interface StateSlice {
|
|
68
|
+
derived: StateHit<"derived">[];
|
|
69
|
+
commitments: StateHit<"commitments">[];
|
|
70
|
+
receipts: StateHit<"receipts">[];
|
|
71
|
+
}
|
|
72
|
+
/** Deterministic order for a state slice: score (best first), then observed_at DESC (latest
|
|
73
|
+
* first), then id ASC. Applied after liveness filtering, before the cap. */
|
|
74
|
+
export declare function compareStateHits(a: StateHit, b: StateHit): number;
|
|
75
|
+
/** Render a state slice as delivery supplements (one header + one line per record) so the
|
|
76
|
+
* section shares the context brief's hard budget and receipt like every other grounding.
|
|
77
|
+
* Empty slice → no supplements at all: a store with zero state records is byte-identical. */
|
|
78
|
+
export declare function stateSupplements(slice: StateSlice, target: string): DeliverySupplement[];
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nuryel.state/1 — the RECORD schemas (the facets that are new record kinds in the store).
|
|
3
|
+
*
|
|
4
|
+
* Kept separate from stateContract.ts (verbs, invariants, hashing) because the store's kind
|
|
5
|
+
* registry in types.ts must reference these schemas, and stateContract imports types.ts —
|
|
6
|
+
* this module imports only zod, the id helpers and the provenance leaf, so there is no cycle.
|
|
7
|
+
*
|
|
8
|
+
* Facets here: done (ActionReceipt), committed (Commitment), current (DerivedState with
|
|
9
|
+
* mandatory dependencies), entity / relationship (external, Landscape-shaped), plus the
|
|
10
|
+
* credential-free ExternalRef ("changed") and DependencyRef they share. Scope is the one
|
|
11
|
+
* graph's partition: organization › team › user › repository.
|
|
12
|
+
*/
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import { edgeId, resourceId } from "./ids.js";
|
|
15
|
+
export declare const RECEIPT_SCHEMA_VERSION: "nuryel.receipt/1";
|
|
16
|
+
export declare const COMMITMENT_SCHEMA_VERSION: "nuryel.commitment/1";
|
|
17
|
+
export declare const DERIVED_SCHEMA_VERSION: "nuryel.derived/1";
|
|
18
|
+
export declare const ENTITY_SCHEMA_VERSION: "nuryel.entity/1";
|
|
19
|
+
export declare const RELATIONSHIP_SCHEMA_VERSION: "nuryel.relationship/1";
|
|
20
|
+
/** organization › team › user › repository — partitions of ONE graph, not separate stores. */
|
|
21
|
+
export declare const SCOPE_KINDS: readonly ["organization", "team", "user", "repository"];
|
|
22
|
+
export declare const ScopeSchema: z.ZodObject<{
|
|
23
|
+
kind: z.ZodEnum<{
|
|
24
|
+
repository: "repository";
|
|
25
|
+
organization: "organization";
|
|
26
|
+
team: "team";
|
|
27
|
+
user: "user";
|
|
28
|
+
}>;
|
|
29
|
+
id: z.ZodString;
|
|
30
|
+
}, z.core.$strict>;
|
|
31
|
+
export type Scope = z.infer<typeof ScopeSchema>;
|
|
32
|
+
export declare const scopePath: (scope: Scope) => string;
|
|
33
|
+
/** "What changed" and "where this came from": a credential-free pointer to an object that
|
|
34
|
+
* stays authoritative in its own system. Nuryel never mirrors its content. */
|
|
35
|
+
export declare const ExternalRefSchema: z.ZodObject<{
|
|
36
|
+
system: z.ZodString;
|
|
37
|
+
object_type: z.ZodString;
|
|
38
|
+
object_key: z.ZodString;
|
|
39
|
+
version: z.ZodOptional<z.ZodString>;
|
|
40
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
41
|
+
observed_at: z.ZodString;
|
|
42
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
43
|
+
}, z.core.$strict>;
|
|
44
|
+
export type ExternalRef = z.infer<typeof ExternalRefSchema>;
|
|
45
|
+
/** The external system's own key, canonicalized so two writers that copied it from the same
|
|
46
|
+
* system agree byte for byte: Unicode NFC, trimmed, internal whitespace collapsed. Case is
|
|
47
|
+
* preserved — the key belongs to the external system, and folding it could merge two of its
|
|
48
|
+
* records. No other guessing: identity here is explicit refs, never similarity. */
|
|
49
|
+
export declare function canonicalObjectKey(key: string): string;
|
|
50
|
+
/** The identity of an external record across writers: system, type and canonical key. Two
|
|
51
|
+
* entities in one partition that carry the same external key are the same thing. */
|
|
52
|
+
export declare function externalKey(ref: Pick<ExternalRef, "system" | "object_type" | "object_key">): string;
|
|
53
|
+
/** The subject an external record is known by, the convention the read verb already uses for
|
|
54
|
+
* receipts (`event:26904`): the object type and the canonical key. When an entity in the
|
|
55
|
+
* partition carries the ref, that entity's id is the subject and this form resolves to it. */
|
|
56
|
+
export declare function subjectOfRef(ref: Pick<ExternalRef, "object_type" | "object_key">): string;
|
|
57
|
+
/** What a derived statement rests on. Exactly what a currentness check re-validates. */
|
|
58
|
+
export declare const DependencyRefSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
59
|
+
kind: z.ZodLiteral<"record">;
|
|
60
|
+
id: z.ZodString;
|
|
61
|
+
record_hash: z.ZodString;
|
|
62
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
63
|
+
kind: z.ZodEnum<{
|
|
64
|
+
repository: "repository";
|
|
65
|
+
organization: "organization";
|
|
66
|
+
team: "team";
|
|
67
|
+
user: "user";
|
|
68
|
+
}>;
|
|
69
|
+
id: z.ZodString;
|
|
70
|
+
}, z.core.$strict>>;
|
|
71
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
72
|
+
kind: z.ZodLiteral<"external">;
|
|
73
|
+
ref: z.ZodObject<{
|
|
74
|
+
system: z.ZodString;
|
|
75
|
+
object_type: z.ZodString;
|
|
76
|
+
object_key: z.ZodString;
|
|
77
|
+
version: z.ZodOptional<z.ZodString>;
|
|
78
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
79
|
+
observed_at: z.ZodString;
|
|
80
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, z.core.$strict>;
|
|
82
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
83
|
+
kind: z.ZodLiteral<"schema">;
|
|
84
|
+
name: z.ZodString;
|
|
85
|
+
fingerprint: z.ZodString;
|
|
86
|
+
}, z.core.$strict>], "kind">;
|
|
87
|
+
export type DependencyRef = z.infer<typeof DependencyRefSchema>;
|
|
88
|
+
/** done — a side effect that happened. Never replayable as a read; idempotency is explicit. */
|
|
89
|
+
export declare const ActionReceiptSchema: z.ZodObject<{
|
|
90
|
+
schema: z.ZodLiteral<"nuryel.receipt/1">;
|
|
91
|
+
id: z.ZodString;
|
|
92
|
+
scope: z.ZodObject<{
|
|
93
|
+
kind: z.ZodEnum<{
|
|
94
|
+
repository: "repository";
|
|
95
|
+
organization: "organization";
|
|
96
|
+
team: "team";
|
|
97
|
+
user: "user";
|
|
98
|
+
}>;
|
|
99
|
+
id: z.ZodString;
|
|
100
|
+
}, z.core.$strict>;
|
|
101
|
+
actor: z.ZodString;
|
|
102
|
+
action_kind: z.ZodString;
|
|
103
|
+
target: z.ZodObject<{
|
|
104
|
+
system: z.ZodString;
|
|
105
|
+
object_type: z.ZodString;
|
|
106
|
+
object_key: z.ZodString;
|
|
107
|
+
version: z.ZodOptional<z.ZodString>;
|
|
108
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
109
|
+
observed_at: z.ZodString;
|
|
110
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
111
|
+
}, z.core.$strict>;
|
|
112
|
+
request_fingerprint: z.ZodString;
|
|
113
|
+
idempotency_key: z.ZodOptional<z.ZodString>;
|
|
114
|
+
state: z.ZodEnum<{
|
|
115
|
+
unknown: "unknown";
|
|
116
|
+
requested: "requested";
|
|
117
|
+
succeeded: "succeeded";
|
|
118
|
+
failed: "failed";
|
|
119
|
+
verified: "verified";
|
|
120
|
+
}>;
|
|
121
|
+
occurred_at: z.ZodString;
|
|
122
|
+
verified_at: z.ZodOptional<z.ZodString>;
|
|
123
|
+
result_fingerprint: z.ZodOptional<z.ZodString>;
|
|
124
|
+
invalidates: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
125
|
+
rests_on: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
126
|
+
kind: z.ZodLiteral<"record">;
|
|
127
|
+
id: z.ZodString;
|
|
128
|
+
record_hash: z.ZodString;
|
|
129
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
130
|
+
kind: z.ZodEnum<{
|
|
131
|
+
repository: "repository";
|
|
132
|
+
organization: "organization";
|
|
133
|
+
team: "team";
|
|
134
|
+
user: "user";
|
|
135
|
+
}>;
|
|
136
|
+
id: z.ZodString;
|
|
137
|
+
}, z.core.$strict>>;
|
|
138
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
139
|
+
kind: z.ZodLiteral<"external">;
|
|
140
|
+
ref: z.ZodObject<{
|
|
141
|
+
system: z.ZodString;
|
|
142
|
+
object_type: z.ZodString;
|
|
143
|
+
object_key: z.ZodString;
|
|
144
|
+
version: z.ZodOptional<z.ZodString>;
|
|
145
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
146
|
+
observed_at: z.ZodString;
|
|
147
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
148
|
+
}, z.core.$strict>;
|
|
149
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
150
|
+
kind: z.ZodLiteral<"schema">;
|
|
151
|
+
name: z.ZodString;
|
|
152
|
+
fingerprint: z.ZodString;
|
|
153
|
+
}, z.core.$strict>], "kind">>>;
|
|
154
|
+
provenance: z.ZodObject<{
|
|
155
|
+
source: z.ZodString;
|
|
156
|
+
confidence: z.ZodNumber;
|
|
157
|
+
evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
158
|
+
last_verified: z.ZodOptional<z.ZodString>;
|
|
159
|
+
}, z.core.$strip>;
|
|
160
|
+
}, z.core.$strict>;
|
|
161
|
+
export type ActionReceipt = z.infer<typeof ActionReceiptSchema>;
|
|
162
|
+
/** committed — an obligation with a due date and an in-force window. */
|
|
163
|
+
export declare const CommitmentSchema: z.ZodObject<{
|
|
164
|
+
schema: z.ZodLiteral<"nuryel.commitment/1">;
|
|
165
|
+
id: z.ZodString;
|
|
166
|
+
scope: z.ZodObject<{
|
|
167
|
+
kind: z.ZodEnum<{
|
|
168
|
+
repository: "repository";
|
|
169
|
+
organization: "organization";
|
|
170
|
+
team: "team";
|
|
171
|
+
user: "user";
|
|
172
|
+
}>;
|
|
173
|
+
id: z.ZodString;
|
|
174
|
+
}, z.core.$strict>;
|
|
175
|
+
subject: z.ZodString;
|
|
176
|
+
title: z.ZodString;
|
|
177
|
+
owner: z.ZodString;
|
|
178
|
+
due: z.ZodString;
|
|
179
|
+
status: z.ZodEnum<{
|
|
180
|
+
open: "open";
|
|
181
|
+
waiting: "waiting";
|
|
182
|
+
done: "done";
|
|
183
|
+
cancelled: "cancelled";
|
|
184
|
+
}>;
|
|
185
|
+
source: z.ZodOptional<z.ZodObject<{
|
|
186
|
+
system: z.ZodString;
|
|
187
|
+
object_type: z.ZodString;
|
|
188
|
+
object_key: z.ZodString;
|
|
189
|
+
version: z.ZodOptional<z.ZodString>;
|
|
190
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
191
|
+
observed_at: z.ZodString;
|
|
192
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
193
|
+
}, z.core.$strict>>;
|
|
194
|
+
evidence_excerpt: z.ZodOptional<z.ZodString>;
|
|
195
|
+
closed_by: z.ZodOptional<z.ZodString>;
|
|
196
|
+
valid_from: z.ZodString;
|
|
197
|
+
valid_to: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
198
|
+
provenance: z.ZodObject<{
|
|
199
|
+
source: z.ZodString;
|
|
200
|
+
confidence: z.ZodNumber;
|
|
201
|
+
evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
202
|
+
last_verified: z.ZodOptional<z.ZodString>;
|
|
203
|
+
}, z.core.$strip>;
|
|
204
|
+
}, z.core.$strict>;
|
|
205
|
+
export type Commitment = z.infer<typeof CommitmentSchema>;
|
|
206
|
+
/** current — a statement that is true now, and on what it rests. Dependencies are mandatory:
|
|
207
|
+
* a derived statement without them cannot be invalidated and therefore cannot be trusted. */
|
|
208
|
+
export declare const DerivedStateSchema: z.ZodObject<{
|
|
209
|
+
schema: z.ZodLiteral<"nuryel.derived/1">;
|
|
210
|
+
id: z.ZodString;
|
|
211
|
+
scope: z.ZodObject<{
|
|
212
|
+
kind: z.ZodEnum<{
|
|
213
|
+
repository: "repository";
|
|
214
|
+
organization: "organization";
|
|
215
|
+
team: "team";
|
|
216
|
+
user: "user";
|
|
217
|
+
}>;
|
|
218
|
+
id: z.ZodString;
|
|
219
|
+
}, z.core.$strict>;
|
|
220
|
+
subject: z.ZodString;
|
|
221
|
+
content: z.ZodString;
|
|
222
|
+
content_hash: z.ZodString;
|
|
223
|
+
dependencies: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
224
|
+
kind: z.ZodLiteral<"record">;
|
|
225
|
+
id: z.ZodString;
|
|
226
|
+
record_hash: z.ZodString;
|
|
227
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
228
|
+
kind: z.ZodEnum<{
|
|
229
|
+
repository: "repository";
|
|
230
|
+
organization: "organization";
|
|
231
|
+
team: "team";
|
|
232
|
+
user: "user";
|
|
233
|
+
}>;
|
|
234
|
+
id: z.ZodString;
|
|
235
|
+
}, z.core.$strict>>;
|
|
236
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
237
|
+
kind: z.ZodLiteral<"external">;
|
|
238
|
+
ref: z.ZodObject<{
|
|
239
|
+
system: z.ZodString;
|
|
240
|
+
object_type: z.ZodString;
|
|
241
|
+
object_key: z.ZodString;
|
|
242
|
+
version: z.ZodOptional<z.ZodString>;
|
|
243
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
244
|
+
observed_at: z.ZodString;
|
|
245
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
246
|
+
}, z.core.$strict>;
|
|
247
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
248
|
+
kind: z.ZodLiteral<"schema">;
|
|
249
|
+
name: z.ZodString;
|
|
250
|
+
fingerprint: z.ZodString;
|
|
251
|
+
}, z.core.$strict>], "kind">>;
|
|
252
|
+
transform_version: z.ZodString;
|
|
253
|
+
computed_at: z.ZodString;
|
|
254
|
+
valid_to: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
255
|
+
state: z.ZodEnum<{
|
|
256
|
+
unknown: "unknown";
|
|
257
|
+
current: "current";
|
|
258
|
+
stale: "stale";
|
|
259
|
+
}>;
|
|
260
|
+
review: z.ZodOptional<z.ZodObject<{
|
|
261
|
+
by: z.ZodString;
|
|
262
|
+
at: z.ZodString;
|
|
263
|
+
previous_hash: z.ZodString;
|
|
264
|
+
reason: z.ZodString;
|
|
265
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
266
|
+
ref: z.ZodObject<{
|
|
267
|
+
system: z.ZodString;
|
|
268
|
+
object_type: z.ZodString;
|
|
269
|
+
object_key: z.ZodString;
|
|
270
|
+
version: z.ZodOptional<z.ZodString>;
|
|
271
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
272
|
+
observed_at: z.ZodString;
|
|
273
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
274
|
+
}, z.core.$strict>;
|
|
275
|
+
excerpt: z.ZodString;
|
|
276
|
+
}, z.core.$strict>>;
|
|
277
|
+
}, z.core.$strict>>;
|
|
278
|
+
provenance: z.ZodObject<{
|
|
279
|
+
source: z.ZodString;
|
|
280
|
+
confidence: z.ZodNumber;
|
|
281
|
+
evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
282
|
+
last_verified: z.ZodOptional<z.ZodString>;
|
|
283
|
+
}, z.core.$strip>;
|
|
284
|
+
}, z.core.$strict>;
|
|
285
|
+
export type DerivedState = z.infer<typeof DerivedStateSchema>;
|
|
286
|
+
/** entity — a customer, an incident, a thread: a non-code node, Landscape-shaped (kind-qualified
|
|
287
|
+
* id, lifecycle, provenance), with provenance pointers instead of mirrored content. Stored in
|
|
288
|
+
* an index file, like resources, because kind-qualified ids are not safe file names. */
|
|
289
|
+
export declare const ExternalEntitySchema: z.ZodObject<{
|
|
290
|
+
schema: z.ZodLiteral<"nuryel.entity/1">;
|
|
291
|
+
id: z.ZodString;
|
|
292
|
+
kind: z.ZodString;
|
|
293
|
+
name: z.ZodString;
|
|
294
|
+
scope: z.ZodObject<{
|
|
295
|
+
kind: z.ZodEnum<{
|
|
296
|
+
repository: "repository";
|
|
297
|
+
organization: "organization";
|
|
298
|
+
team: "team";
|
|
299
|
+
user: "user";
|
|
300
|
+
}>;
|
|
301
|
+
id: z.ZodString;
|
|
302
|
+
}, z.core.$strict>;
|
|
303
|
+
refs: z.ZodArray<z.ZodObject<{
|
|
304
|
+
system: z.ZodString;
|
|
305
|
+
object_type: z.ZodString;
|
|
306
|
+
object_key: z.ZodString;
|
|
307
|
+
version: z.ZodOptional<z.ZodString>;
|
|
308
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
309
|
+
observed_at: z.ZodString;
|
|
310
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
311
|
+
}, z.core.$strict>>;
|
|
312
|
+
attributes: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>>;
|
|
313
|
+
lifecycle: z.ZodDefault<z.ZodEnum<{
|
|
314
|
+
active: "active";
|
|
315
|
+
deprecated: "deprecated";
|
|
316
|
+
retired: "retired";
|
|
317
|
+
}>>;
|
|
318
|
+
merged_into: z.ZodOptional<z.ZodString>;
|
|
319
|
+
provenance: z.ZodObject<{
|
|
320
|
+
source: z.ZodString;
|
|
321
|
+
confidence: z.ZodNumber;
|
|
322
|
+
evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
323
|
+
last_verified: z.ZodOptional<z.ZodString>;
|
|
324
|
+
}, z.core.$strip>;
|
|
325
|
+
created_at: z.ZodString;
|
|
326
|
+
updated_at: z.ZodString;
|
|
327
|
+
}, z.core.$strict>;
|
|
328
|
+
export type ExternalEntity = z.infer<typeof ExternalEntitySchema>;
|
|
329
|
+
/** relationship — rides the same identity rule as the graph's edges. Index-file stored. */
|
|
330
|
+
export declare const StateRelationshipSchema: z.ZodObject<{
|
|
331
|
+
schema: z.ZodLiteral<"nuryel.relationship/1">;
|
|
332
|
+
id: z.ZodString;
|
|
333
|
+
from: z.ZodString;
|
|
334
|
+
to: z.ZodString;
|
|
335
|
+
type: z.ZodString;
|
|
336
|
+
scope: z.ZodObject<{
|
|
337
|
+
kind: z.ZodEnum<{
|
|
338
|
+
repository: "repository";
|
|
339
|
+
organization: "organization";
|
|
340
|
+
team: "team";
|
|
341
|
+
user: "user";
|
|
342
|
+
}>;
|
|
343
|
+
id: z.ZodString;
|
|
344
|
+
}, z.core.$strict>;
|
|
345
|
+
reason: z.ZodDefault<z.ZodString>;
|
|
346
|
+
observation_hash: z.ZodOptional<z.ZodString>;
|
|
347
|
+
evidence: z.ZodOptional<z.ZodObject<{
|
|
348
|
+
system: z.ZodString;
|
|
349
|
+
object_type: z.ZodString;
|
|
350
|
+
object_key: z.ZodString;
|
|
351
|
+
version: z.ZodOptional<z.ZodString>;
|
|
352
|
+
content_hash: z.ZodOptional<z.ZodString>;
|
|
353
|
+
observed_at: z.ZodString;
|
|
354
|
+
locator: z.ZodOptional<z.ZodString>;
|
|
355
|
+
}, z.core.$strict>>;
|
|
356
|
+
lifecycle: z.ZodOptional<z.ZodEnum<{
|
|
357
|
+
active: "active";
|
|
358
|
+
retired: "retired";
|
|
359
|
+
}>>;
|
|
360
|
+
provenance: z.ZodObject<{
|
|
361
|
+
source: z.ZodString;
|
|
362
|
+
confidence: z.ZodNumber;
|
|
363
|
+
evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
364
|
+
last_verified: z.ZodOptional<z.ZodString>;
|
|
365
|
+
}, z.core.$strip>;
|
|
366
|
+
}, z.core.$strict>;
|
|
367
|
+
export type StateRelationship = z.infer<typeof StateRelationshipSchema>;
|
|
368
|
+
/** DNA facet: existing Project DNA profiles, keyed by scope. No new schema — the reference only. */
|
|
369
|
+
export declare const DnaFacetRefSchema: z.ZodObject<{
|
|
370
|
+
schema: z.ZodLiteral<"hunch.project-dna/1">;
|
|
371
|
+
scope: z.ZodObject<{
|
|
372
|
+
kind: z.ZodEnum<{
|
|
373
|
+
repository: "repository";
|
|
374
|
+
organization: "organization";
|
|
375
|
+
team: "team";
|
|
376
|
+
user: "user";
|
|
377
|
+
}>;
|
|
378
|
+
id: z.ZodString;
|
|
379
|
+
}, z.core.$strict>;
|
|
380
|
+
profile_id: z.ZodString;
|
|
381
|
+
}, z.core.$strict>;
|
|
382
|
+
export declare const entityId: typeof resourceId;
|
|
383
|
+
export declare const relationshipId: typeof edgeId;
|
|
@@ -127,8 +127,16 @@ export const DerivedStateSchema = z.object({
|
|
|
127
127
|
computed_at: z.string().regex(ISO),
|
|
128
128
|
valid_to: z.string().regex(ISO).nullable().default(null),
|
|
129
129
|
state: z.enum(["current", "stale", "unknown"]),
|
|
130
|
+
/** Per-observation withdrawal. Original assertion, author and dependencies stay intact. */
|
|
131
|
+
review: z.object({
|
|
132
|
+
by: z.string().regex(TOKEN), at: z.string().regex(ISO), previous_hash: z.string().regex(SHA256), reason: z.string().trim().min(1).max(600),
|
|
133
|
+
evidence: z.array(z.object({ ref: ExternalRefSchema, excerpt: z.string().trim().min(1).max(1200) }).strict()).min(1).max(8),
|
|
134
|
+
}).strict().optional(),
|
|
130
135
|
provenance: ProvenanceSchema,
|
|
131
|
-
}).strict()
|
|
136
|
+
}).strict().superRefine((record, ctx) => {
|
|
137
|
+
if (record.review && record.state !== 'stale')
|
|
138
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['review'], message: 'withdrawal review belongs only to a stale observation' });
|
|
139
|
+
});
|
|
132
140
|
const AttributeValue = z.union([z.string().max(2048), z.number().finite(), z.boolean(), z.null()]);
|
|
133
141
|
/** entity — a customer, an incident, a thread: a non-code node, Landscape-shaped (kind-qualified
|
|
134
142
|
* id, lifecycle, provenance), with provenance pointers instead of mirrored content. Stored in
|
|
@@ -175,10 +183,17 @@ export const StateRelationshipSchema = z.object({
|
|
|
175
183
|
type: z.string().regex(/^[a-z][a-z0-9_]{0,63}$/),
|
|
176
184
|
scope: ScopeSchema,
|
|
177
185
|
reason: z.string().max(1024).default(""),
|
|
186
|
+
/** observation_about is a one-hop projection, never an entity merge or a copied fact. */
|
|
187
|
+
observation_hash: z.string().regex(SHA256).optional(),
|
|
188
|
+
evidence: ExternalRefSchema.optional(),
|
|
189
|
+
lifecycle: z.enum(["active", "retired"]).optional(),
|
|
178
190
|
provenance: ProvenanceSchema,
|
|
179
191
|
}).strict().superRefine((rel, ctx) => {
|
|
180
192
|
if (rel.id !== edgeId(rel.from, rel.to, rel.type))
|
|
181
193
|
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["id"], message: "relationship id must derive from its endpoints and type" });
|
|
194
|
+
if (rel.type === "observation_about" && (!/^nds_[a-f0-9]{24}$/.test(rel.from) || !rel.observation_hash || !rel.evidence?.content_hash || !rel.reason.trim() || rel.to.length > 512 || rel.to === rel.from)) {
|
|
195
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "observation_about requires an observation id/hash, a subject, reason and hashed external evidence of the explicit association" });
|
|
196
|
+
}
|
|
182
197
|
});
|
|
183
198
|
/** DNA facet: existing Project DNA profiles, keyed by scope. No new schema — the reference only. */
|
|
184
199
|
export const DnaFacetRefSchema = z.object({
|