instar 1.3.948 → 1.3.949
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/dist/messaging/detectors/assertUserVisible.d.ts +3 -0
- package/dist/messaging/detectors/assertUserVisible.d.ts.map +1 -1
- package/dist/messaging/detectors/assertUserVisible.js +17 -1
- package/dist/messaging/detectors/assertUserVisible.js.map +1 -1
- package/dist/messaging/detectors/clock.d.ts +14 -0
- package/dist/messaging/detectors/clock.d.ts.map +1 -0
- package/dist/messaging/detectors/clock.js +14 -0
- package/dist/messaging/detectors/clock.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.949.md +18 -0
- package/upgrades/side-effects/ux-first-enforcement-inc3.md +5 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Deterministic UX assertions for Tier-3 user-surface tests. */
|
|
2
|
+
import type { Clock } from './clock.js';
|
|
2
3
|
/** Reject internal identifiers, paths, config keys, and known implementation jargon. */
|
|
3
4
|
export declare function assertPlainEnglish(text: unknown): asserts text is string;
|
|
4
5
|
/** Every failure must explain what happened and give the user a next action. */
|
|
@@ -8,4 +9,6 @@ export declare function assertHonestFailure(state: unknown): asserts state is {
|
|
|
8
9
|
};
|
|
9
10
|
/** A queue must not contain an expired/stale entry that can be redelivered. */
|
|
10
11
|
export declare function assertNoZombie(queue: unknown): asserts queue is Array<Record<string, unknown>>;
|
|
12
|
+
/** Assert that a visible event landed within its declared bound. */
|
|
13
|
+
export declare function assertTimely(events: unknown, boundMs: number, clock: Clock): void;
|
|
11
14
|
//# sourceMappingURL=assertUserVisible.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assertUserVisible.d.ts","sourceRoot":"","sources":["../../../src/messaging/detectors/assertUserVisible.ts"],"names":[],"mappings":"AAAA,iEAAiE;
|
|
1
|
+
{"version":3,"file":"assertUserVisible.d.ts","sourceRoot":"","sources":["../../../src/messaging/detectors/assertUserVisible.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAWxC,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAKxE;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAO7G;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAa9F;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAWjF"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Deterministic UX assertions for Tier-3 user-surface tests. */
|
|
2
1
|
const INTERNAL_ID = /\b(?:CMT|ACT|PR)[-_#]?\d+\b/i;
|
|
3
2
|
const FILE_PATH = /(?:^|\s)(?:\/|\.\.\/|src\/|tests\/)[^\s]+/;
|
|
4
3
|
const CONFIG_KEY = /\b[a-z][a-z0-9]*(?:\.[a-z][a-z0-9]*){2,}\b/;
|
|
@@ -44,4 +43,21 @@ export function assertNoZombie(queue) {
|
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
}
|
|
46
|
+
/** Assert that a visible event landed within its declared bound. */
|
|
47
|
+
export function assertTimely(events, boundMs, clock) {
|
|
48
|
+
if (!Array.isArray(events) || events.length === 0)
|
|
49
|
+
throw new Error('timely response event is missing');
|
|
50
|
+
if (!Number.isFinite(boundMs) || boundMs < 0)
|
|
51
|
+
throw new Error('timely bound must be non-negative');
|
|
52
|
+
if (!clock || typeof clock.now !== 'function')
|
|
53
|
+
throw new Error('timely assertion requires an injected clock');
|
|
54
|
+
const now = clock.now();
|
|
55
|
+
const visible = events.find((event) => event && typeof event === 'object' && event.userVisible !== false);
|
|
56
|
+
if (!visible || typeof visible.startedAt !== 'number' || typeof visible.at !== 'number') {
|
|
57
|
+
throw new Error('timely response event is malformed');
|
|
58
|
+
}
|
|
59
|
+
const event = visible;
|
|
60
|
+
if (event.at > now || event.at - event.startedAt > boundMs)
|
|
61
|
+
throw new Error('user-visible response exceeded its time bound');
|
|
62
|
+
}
|
|
47
63
|
//# sourceMappingURL=assertUserVisible.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assertUserVisible.js","sourceRoot":"","sources":["../../../src/messaging/detectors/assertUserVisible.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assertUserVisible.js","sourceRoot":"","sources":["../../../src/messaging/detectors/assertUserVisible.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Small clock seam for deterministic user-visible timing assertions. */
|
|
2
|
+
export interface Clock {
|
|
3
|
+
now(): number;
|
|
4
|
+
}
|
|
5
|
+
export declare class RealClock implements Clock {
|
|
6
|
+
now(): number;
|
|
7
|
+
}
|
|
8
|
+
export declare class TestClock implements Clock {
|
|
9
|
+
private current;
|
|
10
|
+
constructor(startAt?: number);
|
|
11
|
+
now(): number;
|
|
12
|
+
advance(ms: number): void;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=clock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../../src/messaging/detectors/clock.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,MAAM,WAAW,KAAK;IAAG,GAAG,IAAI,MAAM,CAAC;CAAE;AAEzC,qBAAa,SAAU,YAAW,KAAK;IACrC,GAAG,IAAI,MAAM;CACd;AAED,qBAAa,SAAU,YAAW,KAAK;IACrC,OAAO,CAAC,OAAO,CAAS;gBACZ,OAAO,SAAI;IACvB,GAAG,IAAI,MAAM;IACb,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;CAI1B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class RealClock {
|
|
2
|
+
now() { return Date.now(); }
|
|
3
|
+
}
|
|
4
|
+
export class TestClock {
|
|
5
|
+
current;
|
|
6
|
+
constructor(startAt = 0) { this.current = startAt; }
|
|
7
|
+
now() { return this.current; }
|
|
8
|
+
advance(ms) {
|
|
9
|
+
if (!Number.isFinite(ms) || ms < 0)
|
|
10
|
+
throw new Error('clock advance must be non-negative');
|
|
11
|
+
this.current += ms;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=clock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.js","sourceRoot":"","sources":["../../../src/messaging/detectors/clock.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,SAAS;IACpB,GAAG,KAAa,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;CACrC;AAED,MAAM,OAAO,SAAS;IACZ,OAAO,CAAS;IACxB,YAAY,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IACpD,GAAG,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACtC,OAAO,CAAC,EAAU;QAChB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC1F,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;IACrB,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-07-25T01:
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-07-25T01:35:29.077Z",
|
|
5
|
+
"instarVersion": "1.3.949",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The UX assertion tier now includes deterministic timing checks using an injected clock. The real messaging E2E covers both a response inside its declared bound and one that exceeds it.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
Tests now verify not only what a user sees and whether failures are honest, but also whether the visible response arrives within its promised time.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
- Reusable `Clock`, `RealClock`, and manually advanced `TestClock`.
|
|
17
|
+
- `assertTimely(events, boundMs, clock)` with no external dependencies.
|
|
18
|
+
- CI-visible within-bound and exceeded-bound messaging cases.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Side-effects review: UX-first enforcement increment 3
|
|
2
|
+
|
|
3
|
+
- Adds a pure injected clock seam and the fourth deterministic UX assertion, `assertTimely`.
|
|
4
|
+
- Exercises both within-bound and exceeded-bound responses in the real messaging E2E; CI remains the proof surface.
|
|
5
|
+
- No network, subprocess, or LLM dependency is introduced.
|