@happyvertical/smrt-ingestion 0.55.6 → 0.55.8
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/AGENTS.md +13 -3
- package/FEEDBACK.md +156 -0
- package/README.md +15 -3
- package/REVIEW.md +137 -0
- package/dist/chunks/{execution-C6HJvl9e.js → execution-C7sTFXFU.js} +375 -11
- package/dist/chunks/execution-C7sTFXFU.js.map +1 -0
- package/dist/chunks/execution-internal-DWteDHM2.js.map +1 -1
- package/dist/chunks/feedback-C3OHD4sA.js +625 -0
- package/dist/chunks/feedback-C3OHD4sA.js.map +1 -0
- package/dist/chunks/{extraction-bseWZuWN.js → proposal-errors-z24VKWnQ.js} +10 -2
- package/dist/chunks/proposal-errors-z24VKWnQ.js.map +1 -0
- package/dist/dto.d.ts +2 -0
- package/dist/dto.d.ts.map +1 -1
- package/dist/execution-internal.d.ts +3 -1
- package/dist/execution-internal.d.ts.map +1 -1
- package/dist/execution.d.ts +15 -1
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +1 -1
- package/dist/feedback-contracts.d.ts +51 -0
- package/dist/feedback-contracts.d.ts.map +1 -0
- package/dist/feedback-dto.d.ts +106 -0
- package/dist/feedback-dto.d.ts.map +1 -0
- package/dist/feedback-internal.d.ts +19 -0
- package/dist/feedback-internal.d.ts.map +1 -0
- package/dist/feedback.d.ts +54 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/manifest.json +34 -1
- package/dist/models.js +1 -1
- package/dist/models.js.map +1 -1
- package/dist/proposal-contracts.d.ts +4 -0
- package/dist/proposal-contracts.d.ts.map +1 -1
- package/dist/proposal-dto.d.ts +4 -0
- package/dist/proposal-dto.d.ts.map +1 -1
- package/dist/proposal-errors.d.ts +5 -0
- package/dist/proposal-errors.d.ts.map +1 -0
- package/dist/proposal-sdk.d.ts.map +1 -1
- package/dist/proposals.d.ts +4 -1
- package/dist/proposals.d.ts.map +1 -1
- package/dist/proposals.js +114 -15
- package/dist/proposals.js.map +1 -1
- package/dist/review-dto.d.ts +115 -0
- package/dist/review-dto.d.ts.map +1 -0
- package/dist/server.d.ts +24 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +146 -54
- package/dist/server.js.map +1 -1
- package/dist/smrt-knowledge.json +97 -14
- package/dist/svelte/components/ActionReview.svelte +232 -0
- package/dist/svelte/components/ActionReview.svelte.d.ts +15 -0
- package/dist/svelte/components/ActionReview.svelte.d.ts.map +1 -0
- package/dist/svelte/components/EvidenceViewer.svelte +31 -0
- package/dist/svelte/components/EvidenceViewer.svelte.d.ts +8 -0
- package/dist/svelte/components/EvidenceViewer.svelte.d.ts.map +1 -0
- package/dist/svelte/components/InboxView.svelte +119 -0
- package/dist/svelte/components/InboxView.svelte.d.ts +9 -0
- package/dist/svelte/components/InboxView.svelte.d.ts.map +1 -0
- package/dist/svelte/components/IntakeInbox.svelte +11 -0
- package/dist/svelte/components/IntakeInbox.svelte.d.ts +10 -0
- package/dist/svelte/components/IntakeInbox.svelte.d.ts.map +1 -0
- package/dist/svelte/components/IntakeReview.svelte +11 -0
- package/dist/svelte/components/IntakeReview.svelte.d.ts +10 -0
- package/dist/svelte/components/IntakeReview.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ReviewView.svelte +243 -0
- package/dist/svelte/components/ReviewView.svelte.d.ts +9 -0
- package/dist/svelte/components/ReviewView.svelte.d.ts.map +1 -0
- package/dist/svelte/i18n.d.ts +72 -0
- package/dist/svelte/i18n.d.ts.map +1 -0
- package/dist/svelte/i18n.js +72 -0
- package/dist/svelte/index.d.ts +5 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +3 -0
- package/dist/svelte/view-utils.d.ts +13 -0
- package/dist/svelte/view-utils.d.ts.map +1 -0
- package/dist/svelte/view-utils.js +96 -0
- package/package.json +49 -22
- package/dist/chunks/execution-C6HJvl9e.js.map +0 -1
- package/dist/chunks/extraction-bseWZuWN.js.map +0 -1
|
@@ -6341,8 +6341,12 @@ var require_ajv = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
6341
6341
|
});
|
|
6342
6342
|
}));
|
|
6343
6343
|
//#endregion
|
|
6344
|
-
//#region src/
|
|
6344
|
+
//#region src/feedback-internal.ts
|
|
6345
6345
|
var import_ajv = /* @__PURE__ */ __toESM(require_ajv(), 1);
|
|
6346
|
+
var feedbackActionTransaction = /* @__PURE__ */ Symbol("ingestion.feedbackActionTransaction");
|
|
6347
|
+
var feedbackDiscoveryContext = /* @__PURE__ */ Symbol("ingestion.feedbackDiscoveryContext");
|
|
6348
|
+
//#endregion
|
|
6349
|
+
//#region src/policy.ts
|
|
6346
6350
|
var lists = [
|
|
6347
6351
|
"handlers",
|
|
6348
6352
|
"operations",
|
|
@@ -6665,9 +6669,15 @@ var IntakeExecutionService = class {
|
|
|
6665
6669
|
return this.tx((db) => this.discoveryContext(db, itemId, handlerId, handlerVersion, work));
|
|
6666
6670
|
}
|
|
6667
6671
|
/** Keep retention restoration outside the supplied foundation transaction. */
|
|
6668
|
-
[discoveryTransaction](run, itemId, work) {
|
|
6672
|
+
[discoveryTransaction](run, itemId, work, requireReview = false) {
|
|
6669
6673
|
return this.withRetention(() => run(async (db) => {
|
|
6670
|
-
const authorize = (handlerId, handlerVersion, callback) => this.discoveryContext(db, itemId, handlerId, handlerVersion, callback)
|
|
6674
|
+
const authorize = (handlerId, handlerVersion, callback) => this.discoveryContext(db, itemId, handlerId, handlerVersion, (context) => callback(context, (model, id2) => this.config.assertTarget({
|
|
6675
|
+
db,
|
|
6676
|
+
scope: this.scope,
|
|
6677
|
+
itemId,
|
|
6678
|
+
model,
|
|
6679
|
+
id: id2
|
|
6680
|
+
})), requireReview);
|
|
6671
6681
|
const result = await work(db, authorize);
|
|
6672
6682
|
for (const [retainedItemId, deadline] of this.retentionIntents.getStore() ?? []) {
|
|
6673
6683
|
const item = await this.restoreRetention(db, retainedItemId, deadline);
|
|
@@ -6676,7 +6686,11 @@ var IntakeExecutionService = class {
|
|
|
6676
6686
|
return result;
|
|
6677
6687
|
}));
|
|
6678
6688
|
}
|
|
6679
|
-
async discoveryContext(db, itemId, handlerId, handlerVersion, work) {
|
|
6689
|
+
async discoveryContext(db, itemId, handlerId, handlerVersion, work, requireReview = false, revalidate) {
|
|
6690
|
+
const review = async () => {
|
|
6691
|
+
const item = await this.item(db, itemId, true);
|
|
6692
|
+
await this.access(db, item, this.handler(handlerId, handlerVersion), "review");
|
|
6693
|
+
};
|
|
6680
6694
|
const authorize = async (callback) => {
|
|
6681
6695
|
const item = await this.item(db, itemId, true);
|
|
6682
6696
|
const handler = this.handler(handlerId, handlerVersion);
|
|
@@ -6701,16 +6715,18 @@ var IntakeExecutionService = class {
|
|
|
6701
6715
|
}
|
|
6702
6716
|
return callback(context);
|
|
6703
6717
|
};
|
|
6718
|
+
if (requireReview) await review();
|
|
6704
6719
|
const result = await authorize(work);
|
|
6705
|
-
await authorize(async () => {});
|
|
6720
|
+
await authorize(revalidate ?? (async () => {}));
|
|
6721
|
+
if (requireReview) await review();
|
|
6706
6722
|
return result;
|
|
6707
6723
|
}
|
|
6708
|
-
async bound(db, actionId, lock = false, expired = false) {
|
|
6724
|
+
async bound(db, actionId, lock = false, expired = false, proposalId) {
|
|
6709
6725
|
const [found] = await this.rows(db, "intake_actions", "id=?", [actionId]);
|
|
6710
6726
|
if (!found) throw new Error("Intake unavailable");
|
|
6711
6727
|
const item = await this.item(db, String(found.item_id), lock, expired);
|
|
6712
6728
|
const [action] = await this.rows(db, "intake_actions", "id=?", [actionId]);
|
|
6713
|
-
const [proposal] = await this.rows(db, "intake_proposals", "action_id=? AND revision=?", [actionId, action.proposal_revision]);
|
|
6729
|
+
const [proposal] = await this.rows(db, "intake_proposals", proposalId ? "action_id=? AND id=?" : "action_id=? AND revision=?", [actionId, proposalId ?? action.proposal_revision]);
|
|
6714
6730
|
if (!proposal) throw new Error("Proposal unavailable");
|
|
6715
6731
|
const binding = object(object(proposal.data).binding);
|
|
6716
6732
|
const handler = this.operation(this.handler(binding.handlerId, binding.handlerVersion));
|
|
@@ -6737,6 +6753,104 @@ var IntakeExecutionService = class {
|
|
|
6737
6753
|
state: String(bound.action.state)
|
|
6738
6754
|
};
|
|
6739
6755
|
}
|
|
6756
|
+
/** Same-executor current review/evidence/target gate for the owning feedback ledger. */
|
|
6757
|
+
/** Join an existing owning transaction; its outer boundary restores retention after rollback. */
|
|
6758
|
+
[feedbackDiscoveryContext](db, itemId, handlerId, handlerVersion, work, revalidate) {
|
|
6759
|
+
const run = (executor) => this.discoveryContext(executor, itemId, handlerId, handlerVersion, work, false, revalidate);
|
|
6760
|
+
return db ? run(db) : this.tx(run);
|
|
6761
|
+
}
|
|
6762
|
+
[feedbackActionTransaction](actionId, reviewer, work, executor, requiredProviders, proposalId) {
|
|
6763
|
+
const operation = async (db) => {
|
|
6764
|
+
const load = async () => {
|
|
6765
|
+
const bound = await this.bound(db, actionId, true, false, proposalId);
|
|
6766
|
+
const { context, permissions } = await this.access(db, bound.item, bound.handler, reviewer ? "review" : "read");
|
|
6767
|
+
if (requiredProviders?.some((provider) => !context.policy.providers.includes(provider))) throw new Error("Feedback source provider unavailable");
|
|
6768
|
+
await this.verifyEvidence(db, bound);
|
|
6769
|
+
for (const target of bound.binding.targetPreconditions) await context.assertTarget(target.model, target.id, bound.action.state === "succeeded" ? void 0 : target.revision);
|
|
6770
|
+
if (bound.binding.plan) {
|
|
6771
|
+
const plan = (await this.rows(db, "intake_plans", "item_id=? AND plan_key=?", [bound.item.id, bound.binding.plan.key])).sort((a, b) => Number(b.revision) - Number(a.revision))[0];
|
|
6772
|
+
if (!plan || plan.digest !== bound.binding.plan.digest) throw new Error("Plan superseded");
|
|
6773
|
+
const data2 = object(plan.data);
|
|
6774
|
+
await this.discoveryContext(db, String(bound.item.id), String(data2.handlerId), String(data2.handlerVersion), async (parent) => {
|
|
6775
|
+
for (const target of object(data2.preview).targetPreconditions) await parent.assertTarget(target.model, target.id, bound.action.state === "succeeded" ? void 0 : target.revision);
|
|
6776
|
+
}, reviewer);
|
|
6777
|
+
}
|
|
6778
|
+
const [analysis] = await this.rows(db, "intake_analyses", "id=?", [bound.proposal.analysis_id]);
|
|
6779
|
+
const [attempt] = await this.rows(db, "intake_analysis_attempts", "id=?", [bound.proposal.analysis_attempt_id]);
|
|
6780
|
+
if (!analysis || !attempt || analysis.current_attempt_id !== attempt.id) throw new Error("Stale feedback source");
|
|
6781
|
+
const data = object(attempt.data);
|
|
6782
|
+
const result2 = {
|
|
6783
|
+
status: data.status,
|
|
6784
|
+
provider: data.provider,
|
|
6785
|
+
model: data.model,
|
|
6786
|
+
version: data.version,
|
|
6787
|
+
output: data.output,
|
|
6788
|
+
usage: data.usage,
|
|
6789
|
+
...Object.hasOwn(data, "error") ? { error: data.error } : {},
|
|
6790
|
+
...Object.hasOwn(data, "confidence") ? { confidence: data.confidence } : {}
|
|
6791
|
+
};
|
|
6792
|
+
if (intakeBindingDigest(result2) !== attempt.output_digest) throw new Error("Analysis output integrity");
|
|
6793
|
+
const input = object(analysis.data);
|
|
6794
|
+
if (intakeBindingDigest({
|
|
6795
|
+
inputs: input.inputs,
|
|
6796
|
+
configuration: input.configuration
|
|
6797
|
+
}) !== analysis.input_digest) throw new Error("Analysis input integrity");
|
|
6798
|
+
if (!this.retained(bound.item)) throw new Error("Feedback unavailable");
|
|
6799
|
+
return {
|
|
6800
|
+
db,
|
|
6801
|
+
context,
|
|
6802
|
+
permissions,
|
|
6803
|
+
review: this.review(bound),
|
|
6804
|
+
itemId: String(bound.item.id),
|
|
6805
|
+
attemptId: String(attempt.id),
|
|
6806
|
+
args: structuredClone(bound.binding.args),
|
|
6807
|
+
analysis: input,
|
|
6808
|
+
result: result2,
|
|
6809
|
+
handlerId: bound.handler.id,
|
|
6810
|
+
handlerVersion: bound.handler.version
|
|
6811
|
+
};
|
|
6812
|
+
};
|
|
6813
|
+
const before = await load();
|
|
6814
|
+
const result = await work(before);
|
|
6815
|
+
const after = await load();
|
|
6816
|
+
if (intakeBindingDigest(before.review) !== intakeBindingDigest(after.review)) throw new Error("Feedback binding changed");
|
|
6817
|
+
if (after.permissions.some((permission) => !before.permissions.includes(permission))) throw new Error("Feedback cannot widen permissions");
|
|
6818
|
+
const prior = before.context.policy, next = after.context.policy;
|
|
6819
|
+
for (const key of [
|
|
6820
|
+
"handlers",
|
|
6821
|
+
"operations",
|
|
6822
|
+
"reviewers",
|
|
6823
|
+
"providers",
|
|
6824
|
+
"access",
|
|
6825
|
+
"automaticHandlers"
|
|
6826
|
+
]) if (next[key].some((value) => !prior[key].includes(value))) throw new Error("Feedback cannot widen policy");
|
|
6827
|
+
for (const key of [
|
|
6828
|
+
"maxAttempts",
|
|
6829
|
+
"maxSteps",
|
|
6830
|
+
"maxBytes",
|
|
6831
|
+
"approvalMs",
|
|
6832
|
+
"leaseMs",
|
|
6833
|
+
"retentionMs"
|
|
6834
|
+
]) if (next[key] > prior[key]) throw new Error("Feedback cannot widen policy");
|
|
6835
|
+
if (prior.requireReview && !next.requireReview || next.minimumCertainty < prior.minimumCertainty || !prior.consequentialAutomation && next.consequentialAutomation) throw new Error("Feedback cannot widen policy");
|
|
6836
|
+
return result;
|
|
6837
|
+
};
|
|
6838
|
+
return executor ? operation(executor) : this.tx(operation);
|
|
6839
|
+
}
|
|
6840
|
+
async feedbackLineage(db, bound) {
|
|
6841
|
+
const [attempt] = await this.rows(db, "intake_analysis_attempts", "id=?", [bound.proposal.analysis_attempt_id]);
|
|
6842
|
+
if (!attempt) throw new Error("Analysis unavailable");
|
|
6843
|
+
const output = object(object(attempt.data).output);
|
|
6844
|
+
if (!output.proposals) return;
|
|
6845
|
+
const feedback = object(object(output.proposals).provenance).feedback;
|
|
6846
|
+
if (!feedback) return;
|
|
6847
|
+
const references = object(object(feedback).selection).examples;
|
|
6848
|
+
if (!Array.isArray(references)) throw new Error("Feedback lineage unavailable");
|
|
6849
|
+
if (references.length === 0) return;
|
|
6850
|
+
if (!this.options.feedback) throw new Error("Feedback configuration unavailable");
|
|
6851
|
+
const { IntakeFeedbackService } = await import("./feedback-C3OHD4sA.js").then((n) => n.n);
|
|
6852
|
+
await new IntakeFeedbackService(this.options, this).assertActionLineage(String(bound.action.id), db, String(bound.proposal.id));
|
|
6853
|
+
}
|
|
6740
6854
|
async getAction(actionId) {
|
|
6741
6855
|
return this.tx(async (db) => {
|
|
6742
6856
|
const [action] = await this.rows(db, "intake_actions", "id=?", [actionId]);
|
|
@@ -6760,9 +6874,175 @@ var IntakeExecutionService = class {
|
|
|
6760
6874
|
const bound = await this.bound(db, actionId);
|
|
6761
6875
|
await this.access(db, bound.item, bound.handler, "read");
|
|
6762
6876
|
if (!this.retained(bound.item)) return expiredReview();
|
|
6877
|
+
try {
|
|
6878
|
+
await this.feedbackLineage(db, bound);
|
|
6879
|
+
} catch (error) {
|
|
6880
|
+
if (bound.action.state !== "succeeded") throw error;
|
|
6881
|
+
await this.successful(db, bound.action, bound.item);
|
|
6882
|
+
return {
|
|
6883
|
+
...this.review(bound),
|
|
6884
|
+
display: {}
|
|
6885
|
+
};
|
|
6886
|
+
}
|
|
6763
6887
|
return this.review(bound);
|
|
6764
6888
|
});
|
|
6765
6889
|
}
|
|
6890
|
+
/** Bounded reload discovery. The cursor is an opaque action ID, never authority. */
|
|
6891
|
+
async listReviews(itemId, input = {}) {
|
|
6892
|
+
const limit = input.limit ?? 20;
|
|
6893
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 50 || input.cursor !== void 0 && !/^[0-9a-f-]{36}$/i.test(input.cursor)) throw new Error("Invalid review page");
|
|
6894
|
+
return this.tx(async (db) => {
|
|
6895
|
+
const item = await this.item(db, itemId, true, true);
|
|
6896
|
+
const rows = (await db.query(`SELECT * FROM intake_actions WHERE tenant_id=? AND confidential_scope_id=? AND item_id=?${input.cursor ? " AND id>?" : ""} ORDER BY id LIMIT ?`, this.scope.tenantId, this.scope.confidentialScopeId, itemId, ...input.cursor ? [input.cursor] : [], limit + 1)).rows;
|
|
6897
|
+
const actions = [];
|
|
6898
|
+
let generationStale = false;
|
|
6899
|
+
for (const action of rows.slice(0, limit)) {
|
|
6900
|
+
const [proposal] = await this.rows(db, "intake_proposals", "action_id=? AND revision=?", [action.id, action.proposal_revision]);
|
|
6901
|
+
if (!proposal) {
|
|
6902
|
+
actions.push({ review: {
|
|
6903
|
+
actionId: String(action.id),
|
|
6904
|
+
proposalId: "",
|
|
6905
|
+
revision: Number(action.proposal_revision),
|
|
6906
|
+
reviewVersion: Number(action.review_version),
|
|
6907
|
+
bindingHash: "",
|
|
6908
|
+
display: {},
|
|
6909
|
+
state: this.retained(item) ? "proposed" : "expired"
|
|
6910
|
+
} });
|
|
6911
|
+
continue;
|
|
6912
|
+
}
|
|
6913
|
+
const tombstone = (state) => ({ review: {
|
|
6914
|
+
actionId: String(action.id),
|
|
6915
|
+
proposalId: String(proposal.id),
|
|
6916
|
+
revision: Number(proposal.revision),
|
|
6917
|
+
reviewVersion: Number(action.review_version),
|
|
6918
|
+
bindingHash: String(proposal.binding_hash),
|
|
6919
|
+
display: {},
|
|
6920
|
+
state
|
|
6921
|
+
} });
|
|
6922
|
+
if (!this.retained(item)) {
|
|
6923
|
+
actions.push(tombstone("expired"));
|
|
6924
|
+
continue;
|
|
6925
|
+
}
|
|
6926
|
+
const bound = await this.bound(db, String(action.id));
|
|
6927
|
+
await this.access(db, bound.item, bound.handler, "read");
|
|
6928
|
+
item.expires_at = bound.item.expires_at;
|
|
6929
|
+
if (!this.retained(bound.item)) {
|
|
6930
|
+
actions.push(tombstone("expired"));
|
|
6931
|
+
continue;
|
|
6932
|
+
}
|
|
6933
|
+
let stale = false;
|
|
6934
|
+
let recoveryAttemptId;
|
|
6935
|
+
const authorizeTargets = async (targets) => {
|
|
6936
|
+
for (const target of targets) if ((await this.config.assertTarget({
|
|
6937
|
+
db,
|
|
6938
|
+
scope: this.scope,
|
|
6939
|
+
itemId,
|
|
6940
|
+
model: target.model,
|
|
6941
|
+
id: target.id
|
|
6942
|
+
})).revision !== target.revision) {
|
|
6943
|
+
generationStale = true;
|
|
6944
|
+
if (bound.action.state !== "succeeded") stale = true;
|
|
6945
|
+
}
|
|
6946
|
+
};
|
|
6947
|
+
await authorizeTargets(bound.binding.targetPreconditions);
|
|
6948
|
+
if (!this.retained(bound.item)) {
|
|
6949
|
+
actions.push(tombstone("expired"));
|
|
6950
|
+
continue;
|
|
6951
|
+
}
|
|
6952
|
+
if (bound.action.state !== "succeeded") {
|
|
6953
|
+
const [analysis] = await this.rows(db, "intake_analyses", "id=?", [proposal.analysis_id]);
|
|
6954
|
+
if (!analysis || Number(analysis.revision) !== Number(item.analysis_revision)) stale = true;
|
|
6955
|
+
else {
|
|
6956
|
+
await this.verifyEvidence(db, bound);
|
|
6957
|
+
const [attempt] = await this.rows(db, "intake_analysis_attempts", "id=? AND analysis_id=?", [proposal.analysis_attempt_id, analysis.id]);
|
|
6958
|
+
if (attempt && ["completed", "partial"].includes(String(attempt.state)) && String(analysis.current_attempt_id) === String(attempt.id)) recoveryAttemptId = String(attempt.id);
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6961
|
+
const entry = {
|
|
6962
|
+
review: this.review(bound),
|
|
6963
|
+
args: structuredClone(bound.binding.args),
|
|
6964
|
+
handlerId: bound.handler.id,
|
|
6965
|
+
handlerVersion: bound.handler.version,
|
|
6966
|
+
attemptId: String(proposal.analysis_attempt_id),
|
|
6967
|
+
dependencies: structuredClone(bound.binding.dependencies)
|
|
6968
|
+
};
|
|
6969
|
+
if (action.state === "succeeded") entry.result = await this.successful(db, action, item);
|
|
6970
|
+
if (bound.binding.plan) {
|
|
6971
|
+
const [plan] = await this.rows(db, "intake_plans", bound.action.state === "succeeded" ? "item_id=? AND plan_key=? AND revision=?" : "item_id=? AND plan_key=? ORDER BY revision DESC LIMIT 1", bound.action.state === "succeeded" ? [
|
|
6972
|
+
itemId,
|
|
6973
|
+
bound.binding.plan.key,
|
|
6974
|
+
bound.binding.plan.revision
|
|
6975
|
+
] : [itemId, bound.binding.plan.key]);
|
|
6976
|
+
if (!plan) throw new Error("Plan unavailable");
|
|
6977
|
+
if (bound.action.state !== "succeeded" && Number(plan.revision) !== bound.binding.plan.revision) stale = true;
|
|
6978
|
+
const planData = object(plan.data);
|
|
6979
|
+
const parent = this.handler(String(planData.handlerId), String(planData.handlerVersion));
|
|
6980
|
+
const parentPreview = object(planData.preview);
|
|
6981
|
+
await this.discoveryContext(db, itemId, parent.id, parent.version, async () => {
|
|
6982
|
+
await authorizeTargets(parentPreview.targetPreconditions);
|
|
6983
|
+
});
|
|
6984
|
+
const steps = planData.steps;
|
|
6985
|
+
entry.plan = {
|
|
6986
|
+
id: String(plan.id),
|
|
6987
|
+
key: String(plan.plan_key),
|
|
6988
|
+
revision: Number(plan.revision),
|
|
6989
|
+
stepIndex: steps.findIndex((step) => step.actionId === action.id),
|
|
6990
|
+
args: object(planData.args),
|
|
6991
|
+
handlerId: parent.id,
|
|
6992
|
+
handlerVersion: parent.version,
|
|
6993
|
+
attemptId: String(proposal.analysis_attempt_id)
|
|
6994
|
+
};
|
|
6995
|
+
}
|
|
6996
|
+
await this.access(db, bound.item, bound.handler, "read");
|
|
6997
|
+
actions.push(!this.retained(bound.item) ? tombstone("expired") : stale ? {
|
|
6998
|
+
...tombstone("stale"),
|
|
6999
|
+
...recoveryAttemptId ? {
|
|
7000
|
+
attemptId: recoveryAttemptId,
|
|
7001
|
+
handlerId: bound.handler.id,
|
|
7002
|
+
handlerVersion: bound.handler.version
|
|
7003
|
+
} : {},
|
|
7004
|
+
...entry.plan ? { stalePlan: {
|
|
7005
|
+
id: entry.plan.id,
|
|
7006
|
+
key: entry.plan.key,
|
|
7007
|
+
revision: entry.plan.revision,
|
|
7008
|
+
handlerId: entry.plan.handlerId,
|
|
7009
|
+
handlerVersion: entry.plan.handlerVersion
|
|
7010
|
+
} } : {}
|
|
7011
|
+
} : entry);
|
|
7012
|
+
}
|
|
7013
|
+
const current = await this.item(db, itemId, false, true);
|
|
7014
|
+
if (!this.retained(current)) {
|
|
7015
|
+
await this.redactExecution(db, current);
|
|
7016
|
+
for (let index = 0; index < actions.length; index++) actions[index] = { review: {
|
|
7017
|
+
...actions[index].review,
|
|
7018
|
+
display: {},
|
|
7019
|
+
state: "expired"
|
|
7020
|
+
} };
|
|
7021
|
+
}
|
|
7022
|
+
for (let index = 0; index < actions.length; index++) {
|
|
7023
|
+
const entry = actions[index];
|
|
7024
|
+
if (!entry.review.proposalId || entry.review.state === "expired" || entry.review.state === "stale") continue;
|
|
7025
|
+
const bound = await this.bound(db, entry.review.actionId);
|
|
7026
|
+
try {
|
|
7027
|
+
await this.feedbackLineage(db, bound);
|
|
7028
|
+
} catch (error) {
|
|
7029
|
+
if (bound.action.state !== "succeeded") throw error;
|
|
7030
|
+
actions[index] = {
|
|
7031
|
+
review: {
|
|
7032
|
+
...entry.review,
|
|
7033
|
+
display: {}
|
|
7034
|
+
},
|
|
7035
|
+
result: await this.successful(db, bound.action, bound.item)
|
|
7036
|
+
};
|
|
7037
|
+
}
|
|
7038
|
+
}
|
|
7039
|
+
return {
|
|
7040
|
+
actions,
|
|
7041
|
+
...generationStale ? { generationStale: true } : {},
|
|
7042
|
+
...rows.length > limit ? { nextCursor: String(rows[limit - 1].id) } : {}
|
|
7043
|
+
};
|
|
7044
|
+
});
|
|
7045
|
+
}
|
|
6766
7046
|
async buildBinding(db, item, input) {
|
|
6767
7047
|
const handler = this.operation(this.handler(input.handlerId, input.handlerVersion));
|
|
6768
7048
|
const { policy, context } = await this.access(db, item, handler, "preview");
|
|
@@ -6850,6 +7130,7 @@ var IntakeExecutionService = class {
|
|
|
6850
7130
|
const replay = prior.find((row) => object(row.data).requestId === input.requestId);
|
|
6851
7131
|
if (replay) {
|
|
6852
7132
|
if (object(replay.data).requestHash !== requestHash) throw new Error("Proposal request conflict");
|
|
7133
|
+
await this.feedbackLineage(db, await this.bound(db, input.actionId, false, false, String(replay.id)));
|
|
6853
7134
|
return {
|
|
6854
7135
|
actionId: input.actionId,
|
|
6855
7136
|
proposalId: String(replay.id),
|
|
@@ -6891,6 +7172,7 @@ var IntakeExecutionService = class {
|
|
|
6891
7172
|
})
|
|
6892
7173
|
});
|
|
6893
7174
|
await db.query("UPDATE intake_actions SET proposal_revision=?,review_version=?,state='waiting_review' WHERE id=? AND tenant_id=? AND confidential_scope_id=?", revision, reviewVersion, action.id, this.scope.tenantId, this.scope.confidentialScopeId);
|
|
7175
|
+
await this.feedbackLineage(db, await this.bound(db, input.actionId, false, false, String(proposal.id)));
|
|
6894
7176
|
return {
|
|
6895
7177
|
actionId: String(action.id),
|
|
6896
7178
|
proposalId: String(proposal.id),
|
|
@@ -6909,6 +7191,62 @@ var IntakeExecutionService = class {
|
|
|
6909
7191
|
return this.publish(db, item, frozen, binding);
|
|
6910
7192
|
});
|
|
6911
7193
|
}
|
|
7194
|
+
/** Capture owner facts in the same transaction; these are never correctness labels. */
|
|
7195
|
+
async feedbackEvent(db, bound, eventId, kind) {
|
|
7196
|
+
if (!this.options.feedback || !this.retained(bound.item)) return;
|
|
7197
|
+
if (!await this.options.feedback.authorize({
|
|
7198
|
+
db,
|
|
7199
|
+
scope: this.scope,
|
|
7200
|
+
itemId: String(bound.item.id),
|
|
7201
|
+
operation: "capture"
|
|
7202
|
+
})) return;
|
|
7203
|
+
const table = kind === "action_decision" ? "intake_review_decisions" : "intake_executions";
|
|
7204
|
+
const [event] = await this.rows(db, table, "id=? AND action_id=?", [eventId, bound.action.id]);
|
|
7205
|
+
if (!event) throw new Error("Feedback event unavailable");
|
|
7206
|
+
const eventData = object(event.data), signal = kind === "action_decision" ? event.decision : event.state;
|
|
7207
|
+
const key = `event:${kind}:${eventId}:${String(signal)}`;
|
|
7208
|
+
const [replay] = await this.rows(db, "intake_feedback", "item_id=? AND request_key=?", [bound.item.id, key]);
|
|
7209
|
+
if (replay) return;
|
|
7210
|
+
const [attempt] = await this.rows(db, "intake_analysis_attempts", "id=?", [bound.proposal.analysis_attempt_id]);
|
|
7211
|
+
const provenance = object(attempt.data), generation = object(object(provenance.output).proposals ?? {});
|
|
7212
|
+
const body = {
|
|
7213
|
+
version: 1,
|
|
7214
|
+
eventId,
|
|
7215
|
+
actionId: bound.action.id,
|
|
7216
|
+
proposalId: bound.proposal.id,
|
|
7217
|
+
revision: Number(bound.proposal.revision),
|
|
7218
|
+
bindingHash: bound.proposal.binding_hash,
|
|
7219
|
+
attemptId: attempt.id,
|
|
7220
|
+
attemptDigest: attempt.output_digest,
|
|
7221
|
+
evidence: bound.binding.evidence,
|
|
7222
|
+
handlerId: bound.handler.id,
|
|
7223
|
+
handlerVersion: bound.handler.version,
|
|
7224
|
+
signal,
|
|
7225
|
+
reviewer: kind === "action_decision" ? eventData.reviewer : null,
|
|
7226
|
+
observedBy: this.scope.actorId,
|
|
7227
|
+
principalId: eventData.principalId ?? null,
|
|
7228
|
+
reason: kind === "action_decision" ? eventData.reason ?? "" : "",
|
|
7229
|
+
resultDigest: event.result_digest ?? null,
|
|
7230
|
+
model: {
|
|
7231
|
+
provider: provenance.provider,
|
|
7232
|
+
model: provenance.model,
|
|
7233
|
+
version: provenance.version
|
|
7234
|
+
},
|
|
7235
|
+
generationProvenance: generation.provenance ?? null
|
|
7236
|
+
};
|
|
7237
|
+
const data = {
|
|
7238
|
+
...body,
|
|
7239
|
+
digest: intakeBindingDigest(body)
|
|
7240
|
+
};
|
|
7241
|
+
if (Buffer.byteLength(canonical(data)) > this.options.feedback.maxBytes) return;
|
|
7242
|
+
await this.insert(db, "intake_feedback", {
|
|
7243
|
+
item_id: bound.item.id,
|
|
7244
|
+
request_key: key,
|
|
7245
|
+
supersedes_id: null,
|
|
7246
|
+
kind,
|
|
7247
|
+
data: canonical(data)
|
|
7248
|
+
});
|
|
7249
|
+
}
|
|
6912
7250
|
async submitDecision(input) {
|
|
6913
7251
|
const frozen = JSON.parse(canonical(input));
|
|
6914
7252
|
id(frozen.requestId);
|
|
@@ -6921,6 +7259,7 @@ var IntakeExecutionService = class {
|
|
|
6921
7259
|
return this.tx(async (db) => {
|
|
6922
7260
|
const bound = await this.bound(db, frozen.actionId, true);
|
|
6923
7261
|
const { policy } = await this.access(db, bound.item, bound.handler, "review");
|
|
7262
|
+
await this.feedbackLineage(db, bound);
|
|
6924
7263
|
const decisions = await this.rows(db, "intake_review_decisions", "action_id=?", [frozen.actionId]);
|
|
6925
7264
|
const requestHash = intakeBindingDigest(frozen);
|
|
6926
7265
|
const replay = decisions.find((row) => object(row.data).requestId === frozen.requestId);
|
|
@@ -6932,7 +7271,7 @@ var IntakeExecutionService = class {
|
|
|
6932
7271
|
if (bound.action.state !== "waiting_review" || Number(bound.proposal.revision) !== frozen.expectedRevision || Number(bound.action.review_version) !== frozen.expectedReviewVersion || bound.proposal.binding_hash !== frozen.bindingHash) throw new Error("Stale review");
|
|
6933
7272
|
await this.verifyEvidence(db, bound);
|
|
6934
7273
|
const expiresAt = new Date(Math.min(time(bound.item.expires_at), this.now().getTime() + policy.approvalMs)).toISOString();
|
|
6935
|
-
await this.insert(db, "intake_review_decisions", {
|
|
7274
|
+
const decisionEvent = await this.insert(db, "intake_review_decisions", {
|
|
6936
7275
|
item_id: bound.item.id,
|
|
6937
7276
|
action_id: bound.action.id,
|
|
6938
7277
|
proposal_id: bound.proposal.id,
|
|
@@ -6950,6 +7289,7 @@ var IntakeExecutionService = class {
|
|
|
6950
7289
|
kind: "human"
|
|
6951
7290
|
})
|
|
6952
7291
|
});
|
|
7292
|
+
await this.feedbackEvent(db, bound, String(decisionEvent.id), "action_decision");
|
|
6953
7293
|
if (frozen.decision === "correct") {
|
|
6954
7294
|
if (bound.binding.plan) throw new Error("Plan correction requires re-expansion");
|
|
6955
7295
|
if (!frozen.correctedArgs) throw new Error("Correction arguments required");
|
|
@@ -6965,8 +7305,10 @@ var IntakeExecutionService = class {
|
|
|
6965
7305
|
dependencies: bound.binding.dependencies
|
|
6966
7306
|
};
|
|
6967
7307
|
const binding = await this.buildBinding(db, bound.item, corrected);
|
|
7308
|
+
await this.feedbackLineage(db, bound);
|
|
6968
7309
|
return this.publish(db, bound.item, corrected, binding);
|
|
6969
7310
|
}
|
|
7311
|
+
await this.feedbackLineage(db, bound);
|
|
6970
7312
|
const state = {
|
|
6971
7313
|
approve: "authorized",
|
|
6972
7314
|
reject: "rejected",
|
|
@@ -6995,6 +7337,7 @@ var IntakeExecutionService = class {
|
|
|
6995
7337
|
}
|
|
6996
7338
|
}
|
|
6997
7339
|
async approved(db, bound) {
|
|
7340
|
+
await this.feedbackLineage(db, bound);
|
|
6998
7341
|
await this.verifyEvidence(db, bound);
|
|
6999
7342
|
if (bound.binding.plan) {
|
|
7000
7343
|
const latest = (await this.rows(db, "intake_plans", "item_id=? AND plan_key=?", [bound.item.id, bound.binding.plan.key])).sort((a, b) => Number(b.revision) - Number(a.revision))[0];
|
|
@@ -7053,6 +7396,7 @@ var IntakeExecutionService = class {
|
|
|
7053
7396
|
const access = await this.access(db, bound.item, bound.handler, "execute");
|
|
7054
7397
|
const consequential = bound.handler.execution.kind === "external" || bound.handler.capability.effect === "destructive" || bound.handler.capability.openWorld;
|
|
7055
7398
|
if (!access.policy.automaticHandlers.includes(bound.handler.id) || consequential && !access.policy.consequentialAutomation || !this.config.evaluateAutomatic) throw new Error("Automatic eligibility revoked");
|
|
7399
|
+
await this.feedbackLineage(db, bound);
|
|
7056
7400
|
const evaluated = await this.config.evaluateAutomatic({
|
|
7057
7401
|
bindingHash: String(bound.proposal.binding_hash),
|
|
7058
7402
|
handlerId: bound.handler.id,
|
|
@@ -7062,6 +7406,7 @@ var IntakeExecutionService = class {
|
|
|
7062
7406
|
}
|
|
7063
7407
|
if (time(object(decision.data).expiresAt) <= this.now().getTime()) throw new Error("Approval required");
|
|
7064
7408
|
await this.verifyEvidence(db, bound);
|
|
7409
|
+
await this.feedbackLineage(db, bound);
|
|
7065
7410
|
return Math.min(time(decisionData.expiresAt), time(bound.item.expires_at));
|
|
7066
7411
|
}
|
|
7067
7412
|
async arguments(db, bound, context) {
|
|
@@ -7169,6 +7514,7 @@ var IntakeExecutionService = class {
|
|
|
7169
7514
|
};
|
|
7170
7515
|
if (!(await db.query("UPDATE intake_actions SET state='succeeded',result_digest=? WHERE id=? AND tenant_id=? AND confidential_scope_id=? AND fence=? AND state IN ('executing','outcome_unknown') RETURNING id", resultDigest, bound.action.id, this.scope.tenantId, this.scope.confidentialScopeId, execution.fence)).rows.length) throw new Error("Execution fence lost");
|
|
7171
7516
|
await db.query("UPDATE intake_executions SET state='succeeded',result_digest=?,data=? WHERE id=? AND tenant_id=? AND confidential_scope_id=?", resultDigest, canonical(data), execution.id, this.scope.tenantId, this.scope.confidentialScopeId);
|
|
7517
|
+
await this.feedbackEvent(db, bound, String(execution.id), "downstream_outcome");
|
|
7172
7518
|
return {
|
|
7173
7519
|
state: "succeeded",
|
|
7174
7520
|
actionId: String(bound.action.id),
|
|
@@ -7212,6 +7558,7 @@ var IntakeExecutionService = class {
|
|
|
7212
7558
|
};
|
|
7213
7559
|
await db.query("UPDATE intake_actions SET state='outcome_unknown' WHERE id=? AND tenant_id=? AND confidential_scope_id=?", actionId, this.scope.tenantId, this.scope.confidentialScopeId);
|
|
7214
7560
|
await db.query("UPDATE intake_executions SET state='outcome_unknown' WHERE id=? AND tenant_id=? AND confidential_scope_id=?", execution2.id, this.scope.tenantId, this.scope.confidentialScopeId);
|
|
7561
|
+
await this.feedbackEvent(db, bound2, String(execution2.id), "downstream_outcome");
|
|
7215
7562
|
return {
|
|
7216
7563
|
state: "outcome_unknown",
|
|
7217
7564
|
actionId
|
|
@@ -7222,6 +7569,7 @@ var IntakeExecutionService = class {
|
|
|
7222
7569
|
return this.principal(db, bound2.item, bound2.handler, "execute", async (context) => {
|
|
7223
7570
|
if (Number(bound2.action.execution_attempt) >= context.policy.maxAttempts) throw new Error("Execution budget exceeded");
|
|
7224
7571
|
const args = await this.arguments(db, bound2, context);
|
|
7572
|
+
await this.feedbackLineage(db, bound2);
|
|
7225
7573
|
const attemptNumber = Number(bound2.action.execution_attempt) + 1;
|
|
7226
7574
|
const fence = Number(bound2.action.fence) + 1;
|
|
7227
7575
|
const execution2 = await this.insert(db, "intake_executions", {
|
|
@@ -7277,6 +7625,7 @@ var IntakeExecutionService = class {
|
|
|
7277
7625
|
error: "domain_failure",
|
|
7278
7626
|
rolledBack: true
|
|
7279
7627
|
} : {}), execution2.id, this.scope.tenantId, this.scope.confidentialScopeId);
|
|
7628
|
+
await this.feedbackEvent(db, bound2, String(execution2.id), "downstream_outcome");
|
|
7280
7629
|
await db.query("UPDATE intake_actions SET state='failed' WHERE id=? AND tenant_id=? AND confidential_scope_id=?", actionId, this.scope.tenantId, this.scope.confidentialScopeId);
|
|
7281
7630
|
return {
|
|
7282
7631
|
state: "failed",
|
|
@@ -7340,6 +7689,10 @@ var IntakeExecutionService = class {
|
|
|
7340
7689
|
if (!this.retained(item)) await this.redactExecution(db, item);
|
|
7341
7690
|
await db.query("UPDATE intake_actions SET state='outcome_unknown' WHERE id=? AND tenant_id=? AND confidential_scope_id=? AND fence=? AND state='executing'", actionId, this.scope.tenantId, this.scope.confidentialScopeId, execution.fence);
|
|
7342
7691
|
await db.query("UPDATE intake_executions SET state='outcome_unknown' WHERE id=? AND tenant_id=? AND confidential_scope_id=? AND state='claimed'", execution.id, this.scope.tenantId, this.scope.confidentialScopeId);
|
|
7692
|
+
await this.feedbackEvent(db, {
|
|
7693
|
+
...bound,
|
|
7694
|
+
item
|
|
7695
|
+
}, String(execution.id), "downstream_outcome");
|
|
7343
7696
|
return {
|
|
7344
7697
|
state: "outcome_unknown",
|
|
7345
7698
|
actionId,
|
|
@@ -7393,6 +7746,10 @@ var IntakeExecutionService = class {
|
|
|
7393
7746
|
...object(execution.data),
|
|
7394
7747
|
reconciliation: observed.kind
|
|
7395
7748
|
}), execution.id, this.scope.tenantId, this.scope.confidentialScopeId);
|
|
7749
|
+
await this.feedbackEvent(db, {
|
|
7750
|
+
...bound,
|
|
7751
|
+
item
|
|
7752
|
+
}, String(execution.id), "downstream_outcome");
|
|
7396
7753
|
return {
|
|
7397
7754
|
state,
|
|
7398
7755
|
actionId,
|
|
@@ -7407,12 +7764,14 @@ var IntakeExecutionService = class {
|
|
|
7407
7764
|
const { current, policy, context } = await this.access(db, bound.item, bound.handler, "execute");
|
|
7408
7765
|
const consequential = bound.handler.execution.kind === "external" || bound.handler.capability.effect === "destructive" || bound.handler.capability.openWorld;
|
|
7409
7766
|
if (bound.action.state !== "waiting_review" || !policy.automaticHandlers.includes(bound.handler.id) || consequential && !policy.consequentialAutomation || !this.config.evaluateAutomatic) throw new Error("Automatic execution unavailable");
|
|
7767
|
+
await this.feedbackLineage(db, bound);
|
|
7410
7768
|
const evaluated = await this.config.evaluateAutomatic({
|
|
7411
7769
|
bindingHash: String(bound.proposal.binding_hash),
|
|
7412
7770
|
handlerId: bound.handler.id,
|
|
7413
7771
|
context
|
|
7414
7772
|
});
|
|
7415
7773
|
if (!evaluated.eligible || !Number.isFinite(evaluated.certainty) || evaluated.certainty < policy.minimumCertainty || evaluated.certainty > 1 || current.policy.filter((layer, index) => index < 3 || layer.automation !== void 0).some((layer) => layer.automation?.evaluationVersion !== evaluated.evaluationVersion)) throw new Error("Automatic execution unavailable");
|
|
7774
|
+
await this.feedbackLineage(db, bound);
|
|
7416
7775
|
await this.verifyEvidence(db, bound);
|
|
7417
7776
|
if (!this.retained(bound.item)) throw new RetentionExpired(String(bound.item.id), time(bound.item.expires_at));
|
|
7418
7777
|
await this.insert(db, "intake_review_decisions", {
|
|
@@ -7471,7 +7830,11 @@ var IntakeExecutionService = class {
|
|
|
7471
7830
|
key: frozen.planKey,
|
|
7472
7831
|
revision: Number(replay.revision),
|
|
7473
7832
|
digest: String(replay.digest),
|
|
7474
|
-
steps: await Promise.all(steps.map(async (step) =>
|
|
7833
|
+
steps: await Promise.all(steps.map(async (step) => {
|
|
7834
|
+
const bound = await this.bound(db, step.actionId);
|
|
7835
|
+
await this.feedbackLineage(db, bound);
|
|
7836
|
+
return this.review(bound);
|
|
7837
|
+
}))
|
|
7475
7838
|
};
|
|
7476
7839
|
}
|
|
7477
7840
|
if (Math.max(0, ...existing.map((plan2) => Number(plan2.revision))) !== frozen.expectedRevision) throw new Error("Plan conflict");
|
|
@@ -7600,6 +7963,7 @@ var IntakeExecutionService = class {
|
|
|
7600
7963
|
}))
|
|
7601
7964
|
})
|
|
7602
7965
|
});
|
|
7966
|
+
for (const review of reviews) await this.feedbackLineage(db, await this.bound(db, review.actionId, false, false, review.proposalId));
|
|
7603
7967
|
return {
|
|
7604
7968
|
id: String(plan.id),
|
|
7605
7969
|
key: frozen.planKey,
|
|
@@ -7662,6 +8026,6 @@ async function continueIntakeReview(service, actionId, task) {
|
|
|
7662
8026
|
return service.applyAction(actionId);
|
|
7663
8027
|
}
|
|
7664
8028
|
//#endregion
|
|
7665
|
-
export {
|
|
8029
|
+
export { feedbackActionTransaction as a, __exportAll as c, resolveIntakePolicy as i, __toESM as l, continueIntakeReview as n, feedbackDiscoveryContext as o, intakeBindingDigest as r, require_ajv as s, IntakeExecutionService as t };
|
|
7666
8030
|
|
|
7667
|
-
//# sourceMappingURL=execution-
|
|
8031
|
+
//# sourceMappingURL=execution-C7sTFXFU.js.map
|