New:Socket for Asana Is Now Available.Learn more
Get Started

once-kernel

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

once-kernel - npm Package Compare versions

Comparing version
0.2.0
to
0.4.0
+172
bin/once-audit.js
#!/usr/bin/env node
/**
* once-audit — find duplicate effects in records you already have.
*
* npx once-kernel-audit records.json --at=created_at --subject=customer,amount --amount=amount --key=idempotency_key
*
* No code, no adoption, no store to install. Reads a JSON array (or JSONL) of
* records exported from wherever you already keep them — a payments table, a
* send log — and reports which look like the same operation happening more
* than once.
*
* JSON only, deliberately. A CSV parser has quoting and encoding edge cases
* that are easy to get subtly wrong, and a silent misparse here is the worst
* possible failure mode: a tool whose whole job is finding money that moved
* twice must not itself introduce an error nobody notices. Export to JSON
* first (a spreadsheet's "Export as JSON," or `jq -s .` on JSONL) rather than
* trust an unaudited CSV reader with financial records.
*
* Field mapping is EXPLICIT, never guessed. Auto-detecting which columns
* mean "the same operation" would be guessing at the one judgment call this
* whole library exists to get right — get it wrong and you either miss real
* duplicates or flag legitimate repeats (a recurring subscription looks
* exactly like a duplicate). You choose the fields; the tool does the
* comparison honestly once you have.
*/
import { readFileSync } from "node:fs";
import { findDuplicates, formatAuditReport } from "../dist/audit.js";
function parseArgs(argv) {
const out = { _: [], windowMs: undefined, minAmount: undefined, json: false };
const fields = { id: undefined, at: undefined, subject: undefined, amount: undefined, key: undefined };
for (const a of argv) {
if (a === "--json") { out.json = true; continue; }
if (a === "--help" || a === "-h") { out.help = true; continue; }
const m = /^--([a-z-]+)=(.*)$/.exec(a);
if (!m) { out._.push(a); continue; }
const [, k, v] = m;
if (k === "id") fields.id = v;
else if (k === "at") fields.at = v;
else if (k === "subject") fields.subject = v.split(",").map((s) => s.trim()).filter(Boolean);
else if (k === "amount") fields.amount = v;
else if (k === "key") fields.key = v;
else if (k === "window-hours") out.windowMs = Number(v) * 3600_000;
else if (k === "min-amount") out.minAmount = Number(v);
else out._.push(a);
}
return { out, fields };
}
const HELP = `once-audit — find duplicate effects in records you already have.
Usage:
npx once-kernel-audit <file.json> --at=<field> --subject=<field1,field2,...> [options]
Required:
--at=FIELD which field holds the timestamp
--subject=FIELDS comma-separated fields that define WHAT was done
(e.g. --subject=customer_id,amount). Leave out
anything that varies between retries of the SAME
operation (timestamps, trace ids, retry counters) --
leave IN anything that makes two operations
genuinely different (payee, currency, plan).
Optional:
--id=FIELD a human-readable row identifier (default: row index)
--amount=FIELD numeric field, used to total duplicate exposure
--key=FIELD an existing idempotency key column, if you have one
(checked before --subject, and reported at high
confidence when it matches)
--window-hours=N treat repeats further apart than this as probably
legitimate (default 24). A subscription charged
monthly must not be reported as a duplicate.
--min-amount=N ignore duplicate groups worth less than this
--json machine-readable output
Input file: a JSON array of objects, or JSONL (one object per line).
Example:
npx once-kernel-audit payments.json --at=created_at --subject=customer,plan --amount=amount --key=idem_key
`;
function loadRecords(path) {
const raw = readFileSync(path, "utf8");
const trimmed = raw.trim();
if (!trimmed) throw new Error(`${path} is empty`);
if (trimmed.startsWith("[")) {
const parsed = JSON.parse(trimmed);
if (!Array.isArray(parsed)) throw new Error(`${path} does not contain a JSON array`);
return parsed;
}
// JSONL: one JSON object per non-empty line.
return trimmed
.split("\n")
.map((l) => l.trim())
.filter(Boolean)
.map((line, i) => {
try {
return JSON.parse(line);
} catch (e) {
throw new Error(`${path}:${i + 1} is not valid JSON (${e.message})`);
}
});
}
function main() {
const { out, fields } = parseArgs(process.argv.slice(2));
if (out.help || out._.length === 0) {
console.log(HELP);
process.exit(out.help ? 0 : 2);
}
const path = out._[0];
if (!fields.at || !fields.subject) {
console.error(
"once-audit: --at and --subject are required -- guessing which fields identify " +
"\"the same operation\" is exactly the judgment call this tool exists to get right, " +
"so it will not auto-detect them.\n\nRun with --help for the field reference.",
);
process.exit(2);
}
let raw;
try {
raw = loadRecords(path);
} catch (e) {
console.error(`once-audit: ${e.message}`);
process.exit(2);
}
const missing = [];
const records = raw.map((row, i) => {
if (!(fields.at in row)) missing.push(`row ${i}: missing "${fields.at}"`);
const subject = {};
for (const f of fields.subject) {
if (!(f in row)) missing.push(`row ${i}: missing subject field "${f}"`);
subject[f] = row[f];
}
return {
id: fields.id && row[fields.id] !== undefined ? String(row[fields.id]) : String(i),
at: row[fields.at],
subject,
amount: fields.amount ? Number(row[fields.amount]) : undefined,
key: fields.key ? row[fields.key] : undefined,
};
});
if (missing.length) {
console.error(
`once-audit: ${missing.length} row(s) are missing a mapped field -- refusing to guess ` +
`a value and silently under- or over-count duplicates.\n` +
missing.slice(0, 10).join("\n") +
(missing.length > 10 ? `\n...and ${missing.length - 10} more` : ""),
);
process.exit(2);
}
const report = findDuplicates(records, {
windowMs: out.windowMs,
minAmount: out.minAmount,
});
if (out.json) {
console.log(JSON.stringify(report, null, 2));
} else {
console.log(formatAuditReport(report));
}
process.exit(0);
}
main();
/**
* One Door — every irreversible action passes a single gate that answers
* three questions before anything fires:
*
* 1. Did this already happen? (once lease — no duplicates)
* 2. Is there budget left for it? (spend ceiling — no runaway loops)
* 3. May it run without a human? (clearance policy — no surprises)
*
* The three checks share one choke point on purpose. Installed separately,
* a rate limiter cannot deduplicate, an idempotency layer cannot budget,
* and a policy engine can do neither atomically. Composed here, the once
* lease provides the atomicity and the other two ride inside it.
*
* Ordering is load-bearing:
*
* - Clearance runs FIRST and is pure: an action that may not run alone
* must not consume budget or claim the key.
* - The lease runs SECOND: a replay returns the stored result WITHOUT
* touching the budget — a retry of yesterday's charge costs nothing.
* - Budget reserves THIRD, before the effect: ten concurrent calls each
* seeing headroom is the race `SpendLimiter` exists to close.
* - A failed effect releases both the reservation and the key, so a
* transient error never strands budget or blocks a legitimate retry.
*/
import { Once } from "./kernel.ts";
import { SpendLimiter } from "./budget.ts";
/** Decides whether an effect may run without a human in the loop. */
export interface ClearancePolicy {
allows(req: DoorRequest): {
allowed: boolean;
reason?: string;
};
}
/** Clears everything. The default — One Door without a policy is dedup+budget. */
export declare class AllowAll implements ClearancePolicy {
allows(): {
allowed: boolean;
};
}
/**
* Clears only listed tools. The deny message names the list so an agent
* reading the refusal knows the block is policy, not failure.
*/
export declare class AllowList implements ClearancePolicy {
private readonly cleared;
constructor(cleared: Iterable<string>);
allows(req: DoorRequest): {
allowed: boolean;
reason?: string;
};
}
export interface DoorRequest {
/** Idempotency key — what makes two attempts "the same action". */
key: string;
/** Payload fingerprinted for conflict detection (RFC 8785). */
payload: unknown;
/** Spend this action represents. Omit (or 0) for non-metered effects. */
amount?: number;
/** Tool/action name — what clearance policies decide on. */
tool?: string;
/** Human-readable label for refusal messages. Defaults to tool or key. */
what?: string;
}
export type DoorRefusal = {
passed: false;
reason: "not_cleared" | "over_budget" | "conflict";
detail: string;
};
export type DoorPass<T> = {
passed: true;
/** True when this call did NOT execute — the stored result was returned. */
replay: boolean;
result: T;
};
export type DoorOutcome<T> = DoorPass<T> | DoorRefusal;
export interface OneDoorOptions {
once?: Once;
budget?: SpendLimiter;
policy?: ClearancePolicy;
/** How long a concurrent caller waits for the executor's result. */
waitTimeoutMs?: number;
pollMs?: number;
}
export declare class OneDoor {
private readonly once;
private readonly budget?;
private readonly policy;
private readonly waitTimeoutMs;
private readonly pollMs;
constructor(opts?: OneDoorOptions);
/** begin(), but a concurrent in-flight holder is waited out, not thrown. */
private claim;
/**
* Pass an effect through the door. Exactly one concurrent caller with the
* same key executes; the rest wait and receive the same result as a replay.
* Refusals are values, not exceptions — an agent can read the reason and
* choose its next move. Only the effect's own error is rethrown.
*/
pass<T>(req: DoorRequest, effect: () => Promise<T>): Promise<DoorOutcome<T>>;
}
//# sourceMappingURL=door.d.ts.map
{"version":3,"file":"door.d.ts","sourceRoot":"","sources":["../src/door.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAGL,IAAI,EAIL,MAAM,aAAa,CAAC;AACrB,OAAO,EAAkB,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3D,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjE;AAED,kFAAkF;AAClF,qBAAa,QAAS,YAAW,eAAe;IAC9C,MAAM,IAAI;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE;CAG/B;AAED;;;GAGG;AACH,qBAAa,SAAU,YAAW,eAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;gBAC1B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC;IAGrC,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAQhE;AAED,MAAM,WAAW,WAAW;IAC1B,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,KAAK,CAAC;IACd,MAAM,EAAE,aAAa,GAAG,aAAa,GAAG,UAAU,CAAC;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,MAAM,EAAE,IAAI,CAAC;IACb,4EAA4E;IAC5E,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,CAAC,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,IAAI,GAAE,cAAmB;IAQrC,4EAA4E;YAC9D,KAAK;IAgBnB;;;;;OAKG;IACG,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CAkFnF"}
/**
* One Door — every irreversible action passes a single gate that answers
* three questions before anything fires:
*
* 1. Did this already happen? (once lease — no duplicates)
* 2. Is there budget left for it? (spend ceiling — no runaway loops)
* 3. May it run without a human? (clearance policy — no surprises)
*
* The three checks share one choke point on purpose. Installed separately,
* a rate limiter cannot deduplicate, an idempotency layer cannot budget,
* and a policy engine can do neither atomically. Composed here, the once
* lease provides the atomicity and the other two ride inside it.
*
* Ordering is load-bearing:
*
* - Clearance runs FIRST and is pure: an action that may not run alone
* must not consume budget or claim the key.
* - The lease runs SECOND: a replay returns the stored result WITHOUT
* touching the budget — a retry of yesterday's charge costs nothing.
* - Budget reserves THIRD, before the effect: ten concurrent calls each
* seeing headroom is the race `SpendLimiter` exists to close.
* - A failed effect releases both the reservation and the key, so a
* transient error never strands budget or blocks a legitimate retry.
*/
import { IdempotencyConflict, InProgressError, Once, ResultTooLarge, WaitTimeout, } from "./kernel.js";
import { BudgetExceeded, SpendLimiter } from "./budget.js";
/** Clears everything. The default — One Door without a policy is dedup+budget. */
export class AllowAll {
allows() {
return { allowed: true };
}
}
/**
* Clears only listed tools. The deny message names the list so an agent
* reading the refusal knows the block is policy, not failure.
*/
export class AllowList {
cleared;
constructor(cleared) {
this.cleared = new Set(cleared);
}
allows(req) {
const tool = req.tool ?? "";
if (this.cleared.has(tool))
return { allowed: true };
return {
allowed: false,
reason: `tool "${tool || "(unnamed)"}" is not on the clearance list`,
};
}
}
export class OneDoor {
once;
budget;
policy;
waitTimeoutMs;
pollMs;
constructor(opts = {}) {
this.once = opts.once ?? new Once();
this.budget = opts.budget;
this.policy = opts.policy ?? new AllowAll();
this.waitTimeoutMs = opts.waitTimeoutMs ?? 30_000;
this.pollMs = opts.pollMs ?? 50;
}
/** begin(), but a concurrent in-flight holder is waited out, not thrown. */
async claim(key, payload) {
const deadline = Date.now() + this.waitTimeoutMs;
for (;;) {
try {
return await this.once.begin(key, payload);
}
catch (err) {
if (err instanceof InProgressError) {
if (Date.now() >= deadline)
throw new WaitTimeout(key, this.waitTimeoutMs);
await new Promise((r) => setTimeout(r, this.pollMs));
continue;
}
throw err;
}
}
}
/**
* Pass an effect through the door. Exactly one concurrent caller with the
* same key executes; the rest wait and receive the same result as a replay.
* Refusals are values, not exceptions — an agent can read the reason and
* choose its next move. Only the effect's own error is rethrown.
*/
async pass(req, effect) {
const label = req.what ?? req.tool ?? req.key;
// 1 · Clearance — pure, costs nothing, consumes nothing.
const verdict = this.policy.allows(req);
if (!verdict.allowed) {
return {
passed: false,
reason: "not_cleared",
detail: verdict.reason ?? `"${label}" is not cleared to run without a human`,
};
}
// 2 · The lease — the atomic heart. A replay never reaches the budget.
let out;
try {
out = await this.claim(req.key, req.payload);
}
catch (err) {
if (err instanceof IdempotencyConflict) {
return {
passed: false,
reason: "conflict",
detail: `key "${req.key}" was already used with a different payload — refusing to guess which is right`,
};
}
throw err;
}
if (!out.execute) {
if (out.record.status === "failed") {
// A hard failure (allowRetry=false) is permanent by the caller's own
// choice — surfacing it as success would be a lie.
throw new Error(out.record.error || `"${label}" previously failed permanently`);
}
return { passed: true, replay: true, result: out.record.result };
}
const token = out.record.fenceToken;
// 3 · Budget — reserve BEFORE the effect; free the key if refused.
let reservation;
if (this.budget && (req.amount ?? 0) > 0) {
try {
reservation = this.budget.reserve({ what: label, amount: req.amount });
}
catch (err) {
await this.once.fail(req.key, token, `over budget: ${label}`, true);
if (err instanceof BudgetExceeded) {
return { passed: false, reason: "over_budget", detail: err.message };
}
throw err;
}
}
// 4 · The effect itself. Its failure is the caller's error, rethrown —
// but never before both the reservation and the key are freed.
let result;
try {
result = await effect();
}
catch (err) {
reservation?.release();
await this.once.fail(req.key, token, err instanceof Error ? err.message : String(err), true);
throw err;
}
// 5 · Settle: spend committed, result recorded, replays served forever.
reservation?.settle();
try {
await this.once.complete(req.key, token, result);
}
catch (err) {
if (err instanceof ResultTooLarge) {
await this.once.complete(req.key, token, {
__door: "result_too_large_to_store",
});
}
else {
throw err;
}
}
return { passed: true, replay: false, result };
}
}
//# sourceMappingURL=door.js.map
{"version":3,"file":"door.js","sourceRoot":"","sources":["../src/door.ts"],"names":[],"mappings":"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"}
+13
-5
{
"name": "once-kernel",
"version": "0.2.0",
"description": "Idempotency kernel for side-effecting operations. 1,000 racing callers, exactly one execution \u2014 proven, not asserted.",
"version": "0.4.0",
"description": "Idempotency kernel for side-effecting operations. 1,000 racing callers, exactly one execution — proven, not asserted.",
"keywords": [

@@ -47,2 +47,6 @@ "idempotency",

},
"./door": {
"types": "./dist/door.d.ts",
"default": "./dist/door.js"
},
"./budget": {

@@ -57,4 +61,5 @@ "types": "./dist/budget.d.ts",

"dist",
"README.md",
"LICENSE"
"LICENSE",
"bin",
"README.md"
],

@@ -64,3 +69,3 @@ "scripts": {

"clean": "rm -rf dist",
"test": "node --experimental-strip-types --no-warnings --test test/canonical.test.ts test/kernel.test.ts test/store-conformance.test.ts test/guard.test.ts test/capabilities.test.ts test/readme.test.ts",
"test": "node --experimental-strip-types --no-warnings --test test/canonical.test.ts test/kernel.test.ts test/store-conformance.test.ts test/guard.test.ts test/capabilities.test.ts test/readme.test.ts test/once-audit-cli.test.ts test/door.test.ts",
"test:storm": "node --experimental-strip-types --no-warnings --test test/storm.test.ts",

@@ -73,3 +78,6 @@ "test:all": "npm run test && npm run test:storm",

"typescript": "^5.7.0"
},
"bin": {
"once-kernel-audit": "bin/once-audit.js"
}
}

@@ -109,2 +109,20 @@ # once-kernel

**No code at all, if you'd rather not write any:**
```bash
npx once-kernel-audit payments.json --at=created_at --subject=customer,plan --amount=amount --key=idem_key
```
Same function, run against a JSON export straight from your terminal — a
payments table dumped to JSON, a send log, anything with records in it.
JSON and JSONL only, deliberately: a CSV parser has quoting and encoding
edge cases that are easy to get subtly wrong, and a silent misparse here is
the worst possible failure mode for a tool whose whole job is finding money
that moved twice. Export to JSON first.
`--at` and `--subject` are required and never guessed — auto-detecting which
fields mean "the same operation" would be guessing at the one judgment call
this tool exists to get right. Run `npx once-kernel-audit --help` for the
full flag reference, or see `bin/once-audit.js`.
Results carry a confidence and the reason they were flagged. A monthly

@@ -119,2 +137,32 @@ subscription looks exactly like a duplicate, so spread-out repeats are reported

### One Door — three checks, one atomic gate
Every irreversible action passes a single gate that answers three questions
before anything fires: **did this already happen? is there budget left? may
it run without a human?** A rate limiter can't deduplicate, an idempotency
layer can't budget, a policy engine can't do either atomically — One Door
composes all three at the same choke point, and a replay never consumes
budget.
```ts
import { OneDoor, AllowList } from "once-kernel/door";
import { SpendLimiter } from "once-kernel/budget";
const door = new OneDoor({
budget: new SpendLimiter({ limit: 50, windowMs: 86_400_000 }), // $50/day
policy: new AllowList(["send_email", "create_invoice"]),
});
const out = await door.pass(
{ key: `invoice:${orderId}`, payload: order, amount: 12.5, tool: "create_invoice" },
() => stripe.invoices.create(...),
);
// out.passed === true → ran exactly once (or replayed with the same result)
// out.passed === false → out.reason: "not_cleared" | "over_budget" | "conflict"
```
Refusals are values, not exceptions — an agent reads the reason and chooses
its next move. Storm-tested: 50 concurrent passes, one execution, budget
charged once.
### Warn before an unguarded effect

@@ -121,0 +169,0 @@