foottrace 1.1.0 → 1.3.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 +121 -2
- package/dist/cause.js +14 -0
- package/dist/esm/cause.d.ts +8 -0
- package/dist/esm/cause.js +5 -0
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/lib/cause/explain.d.ts +5 -0
- package/dist/esm/lib/cause/explain.js +114 -0
- package/dist/esm/lib/cause/queryMemo.d.ts +18 -0
- package/dist/esm/lib/cause/queryMemo.js +46 -0
- package/dist/esm/lib/cause/ranking.d.ts +6 -0
- package/dist/esm/lib/cause/ranking.js +10 -0
- package/dist/esm/lib/cause/recordAdapter.d.ts +9 -0
- package/dist/esm/lib/cause/recordAdapter.js +42 -0
- package/dist/esm/lib/cause/recordChildren.d.ts +4 -0
- package/dist/esm/lib/cause/recordChildren.js +78 -0
- package/dist/esm/lib/cause/recordControl.d.ts +13 -0
- package/dist/esm/lib/cause/recordControl.js +66 -0
- package/dist/esm/lib/cause/recordCoverage.d.ts +24 -0
- package/dist/esm/lib/cause/recordCoverage.js +87 -0
- package/dist/esm/lib/cause/recordIdentity.d.ts +9 -0
- package/dist/esm/lib/cause/recordIdentity.js +67 -0
- package/dist/esm/lib/cause/recordInspection.d.ts +4 -0
- package/dist/esm/lib/cause/recordInspection.js +86 -0
- package/dist/esm/lib/cause/recordLoading.d.ts +7 -0
- package/dist/esm/lib/cause/recordLoading.js +116 -0
- package/dist/esm/lib/cause/recordQuery.d.ts +9 -0
- package/dist/esm/lib/cause/recordQuery.js +22 -0
- package/dist/esm/lib/cause/recordScope.d.ts +8 -0
- package/dist/esm/lib/cause/recordScope.js +60 -0
- package/dist/esm/lib/cause/recordTypes.d.ts +67 -0
- package/dist/esm/lib/cause/recordTypes.js +1 -0
- package/dist/esm/lib/cause/recordValidation.d.ts +33 -0
- package/dist/esm/lib/cause/recordValidation.js +198 -0
- package/dist/esm/lib/cause/session.d.ts +30 -0
- package/dist/esm/lib/cause/session.js +164 -0
- package/dist/esm/lib/cause/storedRecordAdapter.d.ts +11 -0
- package/dist/esm/lib/cause/storedRecordAdapter.js +63 -0
- package/dist/esm/lib/cause/strategies.d.ts +3 -0
- package/dist/esm/lib/cause/strategies.js +21 -0
- package/dist/esm/lib/cause/types.d.ts +91 -0
- package/dist/esm/lib/cause/types.js +1 -0
- package/dist/esm/lib/cause/validation.d.ts +24 -0
- package/dist/esm/lib/cause/validation.js +117 -0
- package/dist/esm/lib/cause/walk.d.ts +12 -0
- package/dist/esm/lib/cause/walk.js +174 -0
- package/dist/esm/lib/evidence/admission.d.ts +31 -0
- package/dist/esm/lib/evidence/admission.js +72 -0
- package/dist/esm/lib/evidence/codes.d.ts +33 -0
- package/dist/esm/lib/evidence/codes.js +28 -0
- package/dist/esm/lib/evidence/requirementTypes.d.ts +46 -0
- package/dist/esm/lib/evidence/requirementTypes.js +1 -0
- package/dist/esm/lib/evidence/requirements.d.ts +24 -0
- package/dist/esm/lib/evidence/requirements.js +185 -0
- package/dist/esm/lib/memory/types.d.ts +4 -1
- package/dist/esm/lib/memory/types.js +1 -1
- package/dist/index.js +5 -1
- package/dist/lib/cause/explain.js +119 -0
- package/dist/lib/cause/queryMemo.js +52 -0
- package/dist/lib/cause/ranking.js +14 -0
- package/dist/lib/cause/recordAdapter.js +48 -0
- package/dist/lib/cause/recordChildren.js +82 -0
- package/dist/lib/cause/recordControl.js +74 -0
- package/dist/lib/cause/recordCoverage.js +99 -0
- package/dist/lib/cause/recordIdentity.js +73 -0
- package/dist/lib/cause/recordInspection.js +90 -0
- package/dist/lib/cause/recordLoading.js +121 -0
- package/dist/lib/cause/recordQuery.js +27 -0
- package/dist/lib/cause/recordScope.js +66 -0
- package/dist/lib/cause/recordTypes.js +2 -0
- package/dist/lib/cause/recordValidation.js +213 -0
- package/dist/lib/cause/session.js +168 -0
- package/dist/lib/cause/storedRecordAdapter.js +67 -0
- package/dist/lib/cause/strategies.js +26 -0
- package/dist/lib/cause/types.js +2 -0
- package/dist/lib/cause/validation.js +133 -0
- package/dist/lib/cause/walk.js +180 -0
- package/dist/lib/evidence/admission.js +80 -0
- package/dist/lib/evidence/codes.js +33 -0
- package/dist/lib/evidence/requirementTypes.js +2 -0
- package/dist/lib/evidence/requirements.js +190 -0
- package/dist/lib/memory/types.js +1 -1
- package/dist/types/cause.d.ts +8 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/lib/cause/explain.d.ts +5 -0
- package/dist/types/lib/cause/queryMemo.d.ts +18 -0
- package/dist/types/lib/cause/ranking.d.ts +6 -0
- package/dist/types/lib/cause/recordAdapter.d.ts +9 -0
- package/dist/types/lib/cause/recordChildren.d.ts +4 -0
- package/dist/types/lib/cause/recordControl.d.ts +13 -0
- package/dist/types/lib/cause/recordCoverage.d.ts +24 -0
- package/dist/types/lib/cause/recordIdentity.d.ts +9 -0
- package/dist/types/lib/cause/recordInspection.d.ts +4 -0
- package/dist/types/lib/cause/recordLoading.d.ts +7 -0
- package/dist/types/lib/cause/recordQuery.d.ts +9 -0
- package/dist/types/lib/cause/recordScope.d.ts +8 -0
- package/dist/types/lib/cause/recordTypes.d.ts +67 -0
- package/dist/types/lib/cause/recordValidation.d.ts +33 -0
- package/dist/types/lib/cause/session.d.ts +30 -0
- package/dist/types/lib/cause/storedRecordAdapter.d.ts +11 -0
- package/dist/types/lib/cause/strategies.d.ts +3 -0
- package/dist/types/lib/cause/types.d.ts +91 -0
- package/dist/types/lib/cause/validation.d.ts +24 -0
- package/dist/types/lib/cause/walk.d.ts +12 -0
- package/dist/types/lib/evidence/admission.d.ts +31 -0
- package/dist/types/lib/evidence/codes.d.ts +33 -0
- package/dist/types/lib/evidence/requirementTypes.d.ts +46 -0
- package/dist/types/lib/evidence/requirements.d.ts +24 -0
- package/dist/types/lib/memory/types.d.ts +4 -1
- package/package.json +67 -13
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ControlDependency } from '../memory/backtrack.js';
|
|
2
|
+
import type { LogAddress } from '../memory/eventPosition.js';
|
|
3
|
+
import type { CommitBundle } from '../memory/types.js';
|
|
4
|
+
import type { Adjacency, Attention, CauseGraph, Gap, GraphContext, NodeId } from './types.js';
|
|
5
|
+
/** Explicit complete maps record absence too; an omitted map means it was not collected. */
|
|
6
|
+
export interface RecordScope {
|
|
7
|
+
readonly address: LogAddress;
|
|
8
|
+
readonly commitLog: readonly unknown[];
|
|
9
|
+
readonly reads?: Readonly<Record<string, readonly string[]>>;
|
|
10
|
+
readonly controlDeps?: Readonly<Record<string, {
|
|
11
|
+
readonly deciderId: string;
|
|
12
|
+
}>>;
|
|
13
|
+
readonly attention?: Readonly<Record<string, readonly Attention[]>>;
|
|
14
|
+
readonly complete?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface RecordNode {
|
|
17
|
+
readonly runtimeStageId: string;
|
|
18
|
+
readonly commitIdx?: number;
|
|
19
|
+
readonly key?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface RecordGraphOptions {
|
|
22
|
+
readonly maxCommits?: number;
|
|
23
|
+
readonly maxFields?: number;
|
|
24
|
+
readonly maxEdges?: number;
|
|
25
|
+
readonly maxScopes?: number;
|
|
26
|
+
readonly loadTimeoutMs?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface RecordCauseGraph extends CauseGraph {
|
|
29
|
+
nodeId(address: LogAddress, node: RecordNode): NodeId;
|
|
30
|
+
/** Rejects with fixed message/code on discovery failure; never reports an unavailable scope as empty. */
|
|
31
|
+
openScope(address: LogAddress, context: GraphContext): Promise<readonly NodeId[]>;
|
|
32
|
+
}
|
|
33
|
+
export interface RecordLoaderResult {
|
|
34
|
+
readonly scope: RecordScope;
|
|
35
|
+
readonly gaps?: readonly Gap['code'][];
|
|
36
|
+
}
|
|
37
|
+
export interface RecordIdentity extends RecordNode {
|
|
38
|
+
readonly address: LogAddress;
|
|
39
|
+
readonly read?: true;
|
|
40
|
+
}
|
|
41
|
+
export interface PreparedRecordScope {
|
|
42
|
+
address: LogAddress;
|
|
43
|
+
log: CommitBundle[];
|
|
44
|
+
reads?: Map<string, string[]>;
|
|
45
|
+
control?: Map<string, ControlDependency>;
|
|
46
|
+
marks?: Map<string, readonly Attention[]>;
|
|
47
|
+
complete: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface RecordLoadFailure {
|
|
50
|
+
failure: Gap['code'];
|
|
51
|
+
}
|
|
52
|
+
export type LoadedRecordScope = PreparedRecordScope | RecordLoadFailure;
|
|
53
|
+
export interface ResolvedRecordNode {
|
|
54
|
+
scope: PreparedRecordScope;
|
|
55
|
+
identity: RecordIdentity;
|
|
56
|
+
commitIndex: number;
|
|
57
|
+
}
|
|
58
|
+
export interface RecordInspection {
|
|
59
|
+
adjacency: Adjacency;
|
|
60
|
+
gaps: readonly Gap[];
|
|
61
|
+
}
|
|
62
|
+
export type RecordScopeHost = (address: LogAddress, context: GraphContext) => RecordLoaderResult | Promise<RecordLoaderResult>;
|
|
63
|
+
export interface RecordScopeLoader {
|
|
64
|
+
loadScope(address: LogAddress, context: GraphContext): Promise<LoadedRecordScope>;
|
|
65
|
+
extraGapCodes(scope: PreparedRecordScope): readonly Gap['code'][] | undefined;
|
|
66
|
+
}
|
|
67
|
+
export type AddRecordGap = (code: Gap['code']) => void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Admission before the existing readers touch untrusted record fields. Payloads never leave this module's graph. */
|
|
2
|
+
import type { LogAddress } from '../memory/eventPosition.js';
|
|
3
|
+
import type { CommitBundle } from '../memory/types.js';
|
|
4
|
+
import type { GapCode } from './types.js';
|
|
5
|
+
import { attention as marksOf } from './validation.js';
|
|
6
|
+
import { EvidenceRefusal } from '../evidence/admission.js';
|
|
7
|
+
export { marksOf };
|
|
8
|
+
/** Loader refusals stay distinct from graph-port refusals so a failed host load keeps its original classification. */
|
|
9
|
+
export declare class RecordRefusal extends EvidenceRefusal {
|
|
10
|
+
readonly code: GapCode;
|
|
11
|
+
constructor(code?: GapCode);
|
|
12
|
+
}
|
|
13
|
+
export declare function recordOwn(value: unknown, key: string): unknown;
|
|
14
|
+
export declare function names(value: unknown, maximum?: number, path?: boolean): string[];
|
|
15
|
+
export declare function recordName(value: unknown, path?: boolean): string;
|
|
16
|
+
export declare function recordList(value: unknown, maximum: number): readonly unknown[];
|
|
17
|
+
export declare function addressOf(value: unknown): LogAddress;
|
|
18
|
+
export declare function spend(budget: {
|
|
19
|
+
left: number;
|
|
20
|
+
}, count: number): void;
|
|
21
|
+
export declare const addressKey: (a: LogAddress) => string;
|
|
22
|
+
/** Iterative bounded copy: data descriptors only, no getters/toJSON/prototypes or opaque class instances. */
|
|
23
|
+
export declare function dataCopy(value: unknown, budget: {
|
|
24
|
+
left: number;
|
|
25
|
+
}): unknown;
|
|
26
|
+
export declare function bundleOf(value: unknown, idx: number, budget: {
|
|
27
|
+
left: number;
|
|
28
|
+
}): CommitBundle;
|
|
29
|
+
export declare function mapOf<T>(value: unknown, limit: number, read: (v: unknown) => T, budget?: {
|
|
30
|
+
left: number;
|
|
31
|
+
}): Map<string, T> | undefined;
|
|
32
|
+
/** Observe native promises by intrinsic without assimilating a data object's then accessor. */
|
|
33
|
+
export declare function projectLoaded<T, R>(work: () => T | Promise<T>, project: (value: T) => R): Promise<R>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { CauseGraph, ExplainOptions, Gap, GraphContext, NodeId, WalkLimits } from './types.js';
|
|
2
|
+
export interface Read<T> {
|
|
3
|
+
readonly value?: T;
|
|
4
|
+
readonly gap?: Gap;
|
|
5
|
+
}
|
|
6
|
+
type Method = 'parents' | 'children' | 'attention' | 'gaps' | 'roots';
|
|
7
|
+
/** One deadline, memo table and work budget per public query, never per graph or store. */
|
|
8
|
+
export declare class Session {
|
|
9
|
+
readonly limits: Required<WalkLimits>;
|
|
10
|
+
readonly context: GraphContext;
|
|
11
|
+
readonly nodes: Set<string>;
|
|
12
|
+
readonly controller: AbortController;
|
|
13
|
+
private readonly cache;
|
|
14
|
+
private calls;
|
|
15
|
+
edges: number;
|
|
16
|
+
private timedOut;
|
|
17
|
+
private readonly deadline;
|
|
18
|
+
private readonly timer;
|
|
19
|
+
private readonly external?;
|
|
20
|
+
private readonly onAbort;
|
|
21
|
+
private readonly methods;
|
|
22
|
+
constructor(graph: CauseGraph, options?: ExplainOptions);
|
|
23
|
+
dispose(): void;
|
|
24
|
+
stopGap(id?: NodeId): Gap | undefined;
|
|
25
|
+
admit(id: NodeId): Gap | undefined;
|
|
26
|
+
hasRoots(): boolean;
|
|
27
|
+
read<T>(method: Method, id: NodeId | undefined, project: (raw: unknown) => T): Promise<Read<T>>;
|
|
28
|
+
invoke<T>(id: NodeId | undefined, work: () => unknown, project: (raw: unknown) => T): Promise<Read<T>>;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LogAddress } from '../memory/eventPosition.js';
|
|
2
|
+
import { type RecordCauseGraph, type RecordGraphOptions, type RecordScope } from './recordAdapter.js';
|
|
3
|
+
import type { GraphContext, MaybePromise } from './types.js';
|
|
4
|
+
export interface StoredRecordScope extends Omit<RecordScope, 'address' | 'commitLog' | 'complete'> {
|
|
5
|
+
readonly entries: readonly unknown[];
|
|
6
|
+
}
|
|
7
|
+
export interface StoredRecordHost {
|
|
8
|
+
loadLog(address: LogAddress, context: GraphContext): MaybePromise<StoredRecordScope>;
|
|
9
|
+
}
|
|
10
|
+
/** Load one address only. The host owns auth/storage; cancellation is forwarded and waiting is independently bounded. */
|
|
11
|
+
export declare function createStoredRecordGraph(host: StoredRecordHost, options?: RecordGraphOptions): RecordCauseGraph;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { GapCode } from '../evidence/codes.js';
|
|
2
|
+
export type { GapCode } from '../evidence/codes.js';
|
|
3
|
+
/** Names and evidence references only. No state values, messages, credentials or business payloads. */
|
|
4
|
+
export type NodeId = string;
|
|
5
|
+
export type AttentionKind = 'error' | 'unknown-effect' | 'gave-up' | 'timeout' | 'retried' | 'quality-drop' | 'not-collected' | 'outlier' | (string & {});
|
|
6
|
+
export type AttentionReason = 'ERROR_RECORDED' | 'UNKNOWN_EFFECT_RECORDED' | 'RETRY_STOP_RECORDED' | 'TIMEOUT_RECORDED' | 'RETRY_RECORDED' | 'QUALITY_DROP_RECORDED' | 'EVIDENCE_NOT_COLLECTED' | 'OUTLIER_RECORDED' | 'BUSINESS_RULE_MATCHED';
|
|
7
|
+
export interface Attention {
|
|
8
|
+
readonly kind: AttentionKind;
|
|
9
|
+
readonly reason: AttentionReason;
|
|
10
|
+
readonly evidence: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
export type Confidence = 'complete' | 'incomplete';
|
|
13
|
+
export interface Gap {
|
|
14
|
+
readonly code: GapCode;
|
|
15
|
+
readonly nodeId?: NodeId;
|
|
16
|
+
readonly evidence: readonly string[];
|
|
17
|
+
}
|
|
18
|
+
export interface GraphEdge {
|
|
19
|
+
readonly nodeId: NodeId;
|
|
20
|
+
readonly kind: 'data' | 'control';
|
|
21
|
+
readonly attribution: 'per-write' | 'stage' | 'recorded-control';
|
|
22
|
+
readonly evidence: readonly string[];
|
|
23
|
+
}
|
|
24
|
+
export interface Adjacency {
|
|
25
|
+
readonly edges: readonly GraphEdge[];
|
|
26
|
+
readonly complete: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface GraphContext {
|
|
29
|
+
readonly signal: AbortSignal;
|
|
30
|
+
}
|
|
31
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
32
|
+
/** A host owns storage, authentication and service resolution. A node may represent a key-qualified write. */
|
|
33
|
+
export interface CauseGraph {
|
|
34
|
+
parents(id: NodeId, context: GraphContext): MaybePromise<Adjacency>;
|
|
35
|
+
children(id: NodeId, context: GraphContext): MaybePromise<Adjacency>;
|
|
36
|
+
attention(id: NodeId, context: GraphContext): MaybePromise<readonly Attention[]>;
|
|
37
|
+
gaps(id: NodeId, context: GraphContext): MaybePromise<readonly Gap[]>;
|
|
38
|
+
/** Optional, bounded discovery seeds; attentionList can instead receive explicit nodeIds. */
|
|
39
|
+
roots?(context: GraphContext): MaybePromise<readonly NodeId[]>;
|
|
40
|
+
}
|
|
41
|
+
export interface TraversedEdge extends Omit<GraphEdge, 'nodeId'> {
|
|
42
|
+
readonly from: NodeId;
|
|
43
|
+
readonly to: NodeId;
|
|
44
|
+
}
|
|
45
|
+
export interface MarkedNode {
|
|
46
|
+
readonly nodeId: NodeId;
|
|
47
|
+
readonly attention: readonly Attention[];
|
|
48
|
+
}
|
|
49
|
+
export interface ImpactResult {
|
|
50
|
+
readonly nodes: readonly NodeId[];
|
|
51
|
+
readonly edges: readonly TraversedEdge[];
|
|
52
|
+
readonly confidence: Confidence;
|
|
53
|
+
readonly gaps: readonly Gap[];
|
|
54
|
+
}
|
|
55
|
+
export interface CauseResult {
|
|
56
|
+
readonly nodeId: NodeId;
|
|
57
|
+
readonly attention: readonly Attention[];
|
|
58
|
+
/** Present only for one supported candidate and complete backward coverage. Not provider-internal proof. */
|
|
59
|
+
readonly rootCause?: NodeId;
|
|
60
|
+
/** Selected node → candidate, following recorded dependency edges. */
|
|
61
|
+
readonly path: readonly NodeId[];
|
|
62
|
+
readonly alternatives: readonly NodeId[];
|
|
63
|
+
readonly impact: ImpactResult;
|
|
64
|
+
readonly confidence: Confidence;
|
|
65
|
+
readonly gaps: readonly Gap[];
|
|
66
|
+
}
|
|
67
|
+
export interface AttentionListResult {
|
|
68
|
+
readonly nodes: readonly MarkedNode[];
|
|
69
|
+
readonly confidence: Confidence;
|
|
70
|
+
readonly gaps: readonly Gap[];
|
|
71
|
+
}
|
|
72
|
+
export interface WalkLimits {
|
|
73
|
+
readonly maxNodes?: number;
|
|
74
|
+
readonly maxDepth?: number;
|
|
75
|
+
readonly maxEdges?: number;
|
|
76
|
+
readonly maxCalls?: number;
|
|
77
|
+
readonly timeoutMs?: number;
|
|
78
|
+
}
|
|
79
|
+
/** A strategy selects a tied best tier of already recorded marked nodes; it cannot introduce identities. */
|
|
80
|
+
export type RootStrategy = (candidates: readonly MarkedNode[], context: GraphContext) => MaybePromise<readonly NodeId[]>;
|
|
81
|
+
/** Reorder all already discovered impact references; never inject or drop evidence. */
|
|
82
|
+
export type ImpactStrategy = (nodes: readonly NodeId[], context: GraphContext) => MaybePromise<readonly NodeId[]>;
|
|
83
|
+
export interface ExplainOptions extends WalkLimits {
|
|
84
|
+
readonly signal?: AbortSignal;
|
|
85
|
+
readonly rankRoots?: RootStrategy;
|
|
86
|
+
readonly rankImpact?: ImpactStrategy;
|
|
87
|
+
}
|
|
88
|
+
export interface AttentionListOptions extends WalkLimits {
|
|
89
|
+
readonly signal?: AbortSignal;
|
|
90
|
+
readonly nodeIds?: readonly NodeId[];
|
|
91
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Adjacency, Attention, Gap, GapCode, NodeId } from './types.js';
|
|
2
|
+
import { EvidenceRefusal } from '../evidence/admission.js';
|
|
3
|
+
/** Graph-port refusals carry their code through Session; loader refusals are handled at the record boundary. */
|
|
4
|
+
export declare class AdmissionError extends EvidenceRefusal {
|
|
5
|
+
readonly code: GapCode;
|
|
6
|
+
constructor(code?: GapCode);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Only ordinary native promise wrappers belong to the async host contract.
|
|
10
|
+
* An own constructor could run an accessor/species during intrinsic then().
|
|
11
|
+
* Exotic wrappers remain the trusted host's responsibility, including rejection handling.
|
|
12
|
+
*/
|
|
13
|
+
export declare function observePromise(raw: unknown, accept: (raw: unknown) => void, reject: (reason: unknown) => void): boolean;
|
|
14
|
+
export declare function graphOwn(value: unknown, key: string): unknown;
|
|
15
|
+
export declare function plain(value: unknown): void;
|
|
16
|
+
export declare function graphName(value: unknown, maximum?: number): string;
|
|
17
|
+
export declare function graphList<T>(value: unknown, maximum: number, read: (item: unknown) => T, overflow?: GapCode): readonly T[];
|
|
18
|
+
export declare const refs: (value: unknown) => readonly string[];
|
|
19
|
+
export declare function attention(value: unknown): readonly Attention[];
|
|
20
|
+
export declare function gaps(value: unknown): readonly Gap[];
|
|
21
|
+
export declare function adjacency(value: unknown, maximum: number): Adjacency;
|
|
22
|
+
export declare const nodeIds: (value: unknown, max: number) => readonly NodeId[];
|
|
23
|
+
export declare const gap: (code: GapCode, nodeId?: NodeId) => Gap;
|
|
24
|
+
export declare function uniqueGaps(items: readonly Gap[]): readonly Gap[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Gap, MarkedNode, NodeId, TraversedEdge } from './types.js';
|
|
2
|
+
import { Session } from './session.js';
|
|
3
|
+
export interface Walk {
|
|
4
|
+
readonly nodes: readonly NodeId[];
|
|
5
|
+
readonly marked: readonly MarkedNode[];
|
|
6
|
+
readonly edges: readonly TraversedEdge[];
|
|
7
|
+
readonly gaps: readonly Gap[];
|
|
8
|
+
}
|
|
9
|
+
/** BFS discovers the shallowest arrival; a repeated diamond node is not a cycle. */
|
|
10
|
+
export declare function walk(session: Session, seeds: readonly NodeId[], direction: 'parents' | 'children'): Promise<Walk>;
|
|
11
|
+
export declare function frontier(result: Walk): readonly MarkedNode[];
|
|
12
|
+
export declare function pathTo(edges: readonly TraversedEdge[], start: NodeId, target: NodeId): readonly NodeId[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { GapCode } from './codes.js';
|
|
2
|
+
/** One refusal representation; subclasses preserve the graph-port and record-loader boundaries. */
|
|
3
|
+
export declare class EvidenceRefusal extends Error {
|
|
4
|
+
readonly code: GapCode;
|
|
5
|
+
constructor(code: GapCode, message: string);
|
|
6
|
+
}
|
|
7
|
+
export type RefuseEvidence = (code?: GapCode) => Error;
|
|
8
|
+
interface DescriptorPolicy {
|
|
9
|
+
readonly translateTrapErrors: boolean;
|
|
10
|
+
readonly requireOwnValue: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Read data descriptors only; each boundary keeps its existing treatment of proxy traps. */
|
|
13
|
+
export declare function ownData(value: unknown, key: string, refuse: RefuseEvidence, policy: DescriptorPolicy): unknown;
|
|
14
|
+
/** Names share one grammar, with explicit limits and the record path separator exception. */
|
|
15
|
+
export declare function boundedName(value: unknown, maximum: number, refuse: RefuseEvidence, path?: boolean): string;
|
|
16
|
+
/** Bound iteration before reading entries, without invoking element accessors. */
|
|
17
|
+
export declare function boundedList<T>(value: unknown, maximum: number, read: (item: unknown) => T, options: {
|
|
18
|
+
readonly refuse: RefuseEvidence;
|
|
19
|
+
readonly overflow: GapCode;
|
|
20
|
+
readonly freeze: boolean;
|
|
21
|
+
readonly descriptors: DescriptorPolicy;
|
|
22
|
+
/** Optional prior shape inspection must refer to the same admitted length. */
|
|
23
|
+
readonly expectedLength?: number;
|
|
24
|
+
/** New boundaries may normalize revoked-array errors without changing existing reader policy. */
|
|
25
|
+
readonly translateArrayErrors?: boolean;
|
|
26
|
+
}): readonly T[];
|
|
27
|
+
/** Charge retained fields against the same mutable allowance across admission helpers. */
|
|
28
|
+
export declare function spendFields(budget: {
|
|
29
|
+
left: number;
|
|
30
|
+
}, count: number, refuse: RefuseEvidence): void;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** One vocabulary; true marks a domain evidence reason, false a trace/admission gap only. */
|
|
2
|
+
export declare const GAP_CODES: Readonly<{
|
|
3
|
+
readonly 'not-collected': true;
|
|
4
|
+
readonly 'untracked-input': false;
|
|
5
|
+
readonly redacted: true;
|
|
6
|
+
readonly conservative: false;
|
|
7
|
+
readonly 'scope-boundary': false;
|
|
8
|
+
readonly 'invalid-data': true;
|
|
9
|
+
readonly unavailable: true;
|
|
10
|
+
readonly timeout: true;
|
|
11
|
+
readonly cancelled: false;
|
|
12
|
+
readonly cycle: false;
|
|
13
|
+
readonly 'node-limit': false;
|
|
14
|
+
readonly 'depth-limit': false;
|
|
15
|
+
readonly 'edge-limit': false;
|
|
16
|
+
readonly 'call-limit': false;
|
|
17
|
+
readonly truncated: false;
|
|
18
|
+
readonly 'strategy-failed': false;
|
|
19
|
+
readonly 'not-checked': true;
|
|
20
|
+
readonly 'no-match': true;
|
|
21
|
+
readonly ambiguous: true;
|
|
22
|
+
readonly stale: true;
|
|
23
|
+
readonly incompatible: true;
|
|
24
|
+
readonly unsupported: true;
|
|
25
|
+
readonly 'not-permitted': true;
|
|
26
|
+
}>;
|
|
27
|
+
export type GapCode = keyof typeof GAP_CODES;
|
|
28
|
+
/** Producer-asserted evidence reasons, excluding traversal and admission bounds. */
|
|
29
|
+
export type RequirementReason = {
|
|
30
|
+
[Code in GapCode]: (typeof GAP_CODES)[Code] extends true ? Code : never;
|
|
31
|
+
}[GapCode];
|
|
32
|
+
export declare const isGapCode: (value: unknown) => value is "not-collected" | "untracked-input" | "redacted" | "conservative" | "scope-boundary" | "invalid-data" | "unavailable" | "timeout" | "cancelled" | "cycle" | "node-limit" | "depth-limit" | "edge-limit" | "call-limit" | "truncated" | "strategy-failed" | "not-checked" | "no-match" | "ambiguous" | "stale" | "incompatible" | "unsupported" | "not-permitted";
|
|
33
|
+
export declare const isRequirementReason: (value: unknown) => value is RequirementReason;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { RequirementReason } from './codes.js';
|
|
2
|
+
/**
|
|
3
|
+
* Existing check wire words; a disposition records a producer assertion, not authorization.
|
|
4
|
+
* `unreachable` means the check could not run; its reason identifies why.
|
|
5
|
+
*/
|
|
6
|
+
export type RequirementCheckDisposition = 'checked-pass' | 'checked-fail' | 'unreachable' | 'not-applicable';
|
|
7
|
+
/** References to a real check and its retained evidence. No synthetic attempt is required or invented. */
|
|
8
|
+
export interface RequirementCheck {
|
|
9
|
+
readonly checkRef: string;
|
|
10
|
+
readonly disposition: RequirementCheckDisposition;
|
|
11
|
+
readonly reason?: RequirementReason;
|
|
12
|
+
/** A namespaced adapter detail ID, never a message, subject or payload. */
|
|
13
|
+
readonly detail?: string;
|
|
14
|
+
readonly evidenceRefs: readonly string[];
|
|
15
|
+
readonly attemptRefs: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
interface RequirementBinding {
|
|
18
|
+
/** This result's identity, not the enclosing artifact reference minted by storage. */
|
|
19
|
+
readonly id: string;
|
|
20
|
+
/** Reference to the requirement definition or policy. */
|
|
21
|
+
readonly requirementRef: string;
|
|
22
|
+
readonly findingRef: string;
|
|
23
|
+
readonly windowRef: string;
|
|
24
|
+
readonly affects: readonly string[];
|
|
25
|
+
readonly evidenceRefs: readonly string[];
|
|
26
|
+
readonly checks: readonly RequirementCheck[];
|
|
27
|
+
/** References into a host-owned closed action registry; never executable tool names or arguments. */
|
|
28
|
+
readonly actionRefs: readonly string[];
|
|
29
|
+
/** A namespaced adapter detail ID, never a message, subject or payload. */
|
|
30
|
+
readonly detail?: string;
|
|
31
|
+
/** Source validity and learned time are separate opaque references; no freshness inference is made. */
|
|
32
|
+
readonly validTimeRef?: string;
|
|
33
|
+
readonly learnedTimeRef?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A producer assertion. Structural admission does not verify its source, scope, bindings, validity or truth.
|
|
37
|
+
* Hosts must verify those facts and must not let a satisfied record override an unresolved affected claim.
|
|
38
|
+
*/
|
|
39
|
+
export type RequirementResult = RequirementBinding & ({
|
|
40
|
+
readonly state: 'satisfied';
|
|
41
|
+
readonly reason?: never;
|
|
42
|
+
} | {
|
|
43
|
+
readonly state: 'unresolved';
|
|
44
|
+
readonly reason: RequirementReason;
|
|
45
|
+
});
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EvidenceRefusal } from './admission.js';
|
|
2
|
+
import { type GapCode } from './codes.js';
|
|
3
|
+
import type { RequirementResult } from './requirementTypes.js';
|
|
4
|
+
/** Fixed per-call ceilings; characters are UTF-16 code units, not serialized transport bytes. */
|
|
5
|
+
export declare const REQUIREMENT_RESULT_LIMITS: Readonly<{
|
|
6
|
+
results: 512;
|
|
7
|
+
checks: 16;
|
|
8
|
+
affects: 32;
|
|
9
|
+
refs: 16;
|
|
10
|
+
name: 512;
|
|
11
|
+
fields: 32768;
|
|
12
|
+
characters: 1048576;
|
|
13
|
+
}>;
|
|
14
|
+
/** No input, field value or originating exception is retained on a refusal. */
|
|
15
|
+
export declare class RequirementValidationError extends EvidenceRefusal {
|
|
16
|
+
constructor(code?: GapCode);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Atomically project detached, frozen reference-only records. This is structural admission only.
|
|
20
|
+
* The host must authenticate producers, resolve authorized artifacts, verify current query/run/scope and
|
|
21
|
+
* domain validity, and enforce every unresolved affects reference before rendering any factual claim.
|
|
22
|
+
* Identifier grammar does not classify secrets; producers must supply non-secret identifiers only.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readRequirementResults(value: unknown): readonly RequirementResult[];
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* types.ts — the record's types: a bundle, its rows, its patches, its encoding, and the
|
|
3
3
|
* execution tree as the record's readers read it.
|
|
4
4
|
*
|
|
5
|
-
* Imports
|
|
5
|
+
* Imports only the record's leaf attention type. The record names nothing outside itself: the engine's frame
|
|
6
6
|
* types — the stage snapshot, flow messages and retention dials — remain in FootPrint's
|
|
7
7
|
* `frameTypes.ts`. The closed record graph is enforced by scripts/check-layering.mjs.
|
|
8
8
|
*/
|
|
9
|
+
import type { Attention } from '../cause/types.js';
|
|
9
10
|
/** A flat key-value bag representing a state patch (overwrite or merge). */
|
|
10
11
|
export interface MemoryPatch {
|
|
11
12
|
[key: string]: any;
|
|
@@ -194,6 +195,8 @@ export type CommitValuesMode = 'full' | 'delta';
|
|
|
194
195
|
* ```
|
|
195
196
|
*/
|
|
196
197
|
export interface ExecutionTree {
|
|
198
|
+
/** Optional recorded business attention; absence does not assert health. */
|
|
199
|
+
readonly attention?: readonly Attention[];
|
|
197
200
|
/** The stage's id (prefixed inside a subflow). `commitStops` reads the root's to place a subflow's seed. */
|
|
198
201
|
readonly id?: string;
|
|
199
202
|
/** `[subflowPath/]stageId#executionIndex` — what a reader keys on. A node without one is not a stage. */
|
package/package.json
CHANGED
|
@@ -1,45 +1,99 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foottrace",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "commonjs",
|
|
5
|
-
"description": "Execution records, replay, time travel and honest attribution
|
|
5
|
+
"description": "Execution records, replay, time travel and honest attribution \u2014 independent of the engine that produced them",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Sanjay Krishna Anbalagan <sanjay@footprintjs.dev>",
|
|
8
|
-
"repository": {
|
|
9
|
-
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/footprintjs/foottrace.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/footprintjs/foottrace/issues"
|
|
14
|
+
},
|
|
10
15
|
"homepage": "https://github.com/footprintjs/foottrace#readme",
|
|
11
|
-
"engines": {
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22"
|
|
18
|
+
},
|
|
12
19
|
"sideEffects": false,
|
|
13
20
|
"main": "./dist/index.js",
|
|
14
21
|
"module": "./dist/esm/index.js",
|
|
15
22
|
"types": "./dist/types/index.d.ts",
|
|
16
|
-
"files": [
|
|
23
|
+
"files": [
|
|
24
|
+
"dist/"
|
|
25
|
+
],
|
|
17
26
|
"exports": {
|
|
18
|
-
".": {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
".": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/esm/index.d.ts",
|
|
30
|
+
"default": "./dist/esm/index.js"
|
|
31
|
+
},
|
|
32
|
+
"require": {
|
|
33
|
+
"types": "./dist/types/index.d.ts",
|
|
34
|
+
"default": "./dist/index.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"./write": {
|
|
38
|
+
"import": {
|
|
39
|
+
"types": "./dist/esm/write.d.ts",
|
|
40
|
+
"default": "./dist/esm/write.js"
|
|
41
|
+
},
|
|
42
|
+
"require": {
|
|
43
|
+
"types": "./dist/types/write.d.ts",
|
|
44
|
+
"default": "./dist/write.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"./paths": {
|
|
48
|
+
"import": {
|
|
49
|
+
"types": "./dist/esm/paths.d.ts",
|
|
50
|
+
"default": "./dist/esm/paths.js"
|
|
51
|
+
},
|
|
52
|
+
"require": {
|
|
53
|
+
"types": "./dist/types/paths.d.ts",
|
|
54
|
+
"default": "./dist/paths.js"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"./package.json": "./package.json",
|
|
58
|
+
"./cause": {
|
|
59
|
+
"import": {
|
|
60
|
+
"types": "./dist/esm/cause.d.ts",
|
|
61
|
+
"default": "./dist/esm/cause.js"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"typesVersions": {
|
|
66
|
+
"*": {
|
|
67
|
+
"write": [
|
|
68
|
+
"dist/types/write.d.ts"
|
|
69
|
+
],
|
|
70
|
+
"paths": [
|
|
71
|
+
"dist/types/paths.d.ts"
|
|
72
|
+
],
|
|
73
|
+
"cause": [
|
|
74
|
+
"dist/esm/cause.d.ts"
|
|
75
|
+
]
|
|
76
|
+
}
|
|
22
77
|
},
|
|
23
|
-
"typesVersions": { "*": { "write": ["dist/types/write.d.ts"], "paths": ["dist/types/paths.d.ts"] } },
|
|
24
78
|
"scripts": {
|
|
25
79
|
"build": "tsc -p tsconfig.json && tsc -p tsconfig.esm.json && node scripts/postbuild-esm.mjs",
|
|
26
80
|
"test": "vitest run",
|
|
27
81
|
"test:coverage": "vitest run --coverage",
|
|
28
82
|
"typecheck": "tsc -p tsconfig.test.json",
|
|
29
83
|
"check:layering": "node scripts/check-layering.mjs",
|
|
30
|
-
"check:package": "publint && attw --pack",
|
|
84
|
+
"check:package": "publint && attw --pack --exclude-entrypoints cause --profile strict && attw --pack --entrypoints cause --profile esm-only",
|
|
31
85
|
"lint": "eslint 'src/**/*.ts'",
|
|
32
86
|
"format": "prettier --check 'src/**/*.ts' 'test/**/*.ts'",
|
|
33
87
|
"test:examples": "tsc -p examples/tsconfig.json",
|
|
34
88
|
"check": "npm run build && npm run typecheck && npm test && npm run check:layering && npm run lint && npm run format && npm run check:package && npm run test:examples"
|
|
35
89
|
},
|
|
36
|
-
"dependencies": {},
|
|
37
90
|
"devDependencies": {
|
|
38
91
|
"@arethetypeswrong/cli": "^0.18.1",
|
|
39
92
|
"@types/node": "^22.0.0",
|
|
40
93
|
"@typescript-eslint/eslint-plugin": "^8.71.1",
|
|
41
94
|
"@typescript-eslint/parser": "^8.71.1",
|
|
42
95
|
"@vitest/coverage-v8": "4.1.11",
|
|
96
|
+
"esbuild": "0.28.2",
|
|
43
97
|
"eslint": "^8.57.1",
|
|
44
98
|
"fast-check": "^4.4.0",
|
|
45
99
|
"prettier": "^2.8.1",
|