instar 1.3.1102 → 1.3.1103
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/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/package.json +1 -1
- package/scripts/ux-impact-lint.mjs +3 -3
- package/src/data/builtin-manifest.json +2 -2
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/upgrades/1.3.1103.md +63 -0
- package/upgrades/side-effects/ux-gate-scaffold-scope.md +152 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedFrom": "source-tree",
|
|
4
4
|
"registrySha256": "5413a0c6ef9ba2bda876b509d1c0bfebe450da3708cd5a5d627d6cb836012d58",
|
|
5
|
-
"packageVersion": "1.3.
|
|
5
|
+
"packageVersion": "1.3.1103",
|
|
6
6
|
"guards": [
|
|
7
7
|
{
|
|
8
8
|
"ref": "docs/canonical-migration-contracts.json",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sha256": "
|
|
2
|
+
"sha256": "134f316424c9c178f1e9512d39504d10c88e6fad36e013596f2e25cff658488f",
|
|
3
3
|
"registrySha256": "5413a0c6ef9ba2bda876b509d1c0bfebe450da3708cd5a5d627d6cb836012d58",
|
|
4
|
-
"packageVersion": "1.3.
|
|
4
|
+
"packageVersion": "1.3.1103"
|
|
5
5
|
}
|
package/package.json
CHANGED
|
@@ -22,12 +22,12 @@ try {
|
|
|
22
22
|
const report = { version: 1, base, head, authorInScope, scope, allowlistedPaths: [], exempt: false, internalError: false };
|
|
23
23
|
const writeReport = () => { if (reportPath) writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`); };
|
|
24
24
|
if (!authorInScope) { report.outOfScopeAuthor = true; await writeReport(); console.log('UX lint: out-of-scope author'); process.exit(0); }
|
|
25
|
-
const allowlisted = names.filter((p) => p === 'src/server/routes.ts' || p === 'src/commands/server.ts' || p.startsWith('src/messaging/') || p.startsWith('src/dashboard/') || p.startsWith('src/templates/'));
|
|
25
|
+
const allowlisted = names.filter((p) => p === 'src/server/routes.ts' || p === 'src/commands/server.ts' || p === 'src/scaffold/templates.ts' || p.startsWith('src/messaging/') || p.startsWith('src/dashboard/') || p.startsWith('src/templates/'));
|
|
26
26
|
report.allowlistedPaths = allowlisted;
|
|
27
27
|
if (allowlisted.length === 0) { await writeReport(); console.log('UX lint: out of scope'); process.exit(0); }
|
|
28
28
|
const diff = execFileSync('git', ['diff', '--unified=0', `${base}...${head}`, '--', ...allowlisted], { encoding: 'utf8' });
|
|
29
29
|
const added = diff.split('\n').filter((line) => line.startsWith('+') && !line.startsWith('+++')).join('\n');
|
|
30
|
-
const refactorOnly = !allowlisted.some((p) => p.startsWith('src/templates/') || p === 'src/server/routes.ts' || p === 'src/commands/server.ts')
|
|
30
|
+
const refactorOnly = !allowlisted.some((p) => p.startsWith('src/templates/') || p === 'src/server/routes.ts' || p === 'src/commands/server.ts' || p === 'src/scaffold/templates.ts')
|
|
31
31
|
&& !/(?:^|\s)[`'\"](?:[^`'\"]+)[`'\"]/.test(added);
|
|
32
32
|
const section = body.match(/^## UX Impact\s*\n([\s\S]*?)(?=^##\s|(?![\s\S]))/im)?.[1]?.trim() || '';
|
|
33
33
|
if (/UX-Impact:\s*refactor-only/i.test(section) && refactorOnly) { report.exempt = true; report.exemption = 'refactor-only'; await writeReport(); console.log('UX lint PASS: deterministic refactor-only exemption'); process.exit(0); }
|
|
@@ -38,7 +38,7 @@ try {
|
|
|
38
38
|
}
|
|
39
39
|
const quoted = [...section.matchAll(/[`'"“]([^`'"”]+)[`'"”]/g)].map((m) => m[1]);
|
|
40
40
|
if (!quoted.some((q) => q.length > 2 && diff.includes(q))) {
|
|
41
|
-
console.error(
|
|
41
|
+
console.error(`::error::UX Impact must quote a concrete string from the USER-FACING paths this PR touches (${allowlisted.join(', ')}). Quotes from other changed files are not checked.`); process.exit(1);
|
|
42
42
|
}
|
|
43
43
|
await writeReport();
|
|
44
44
|
console.log(`UX lint PASS: ${allowlisted.length} allowlisted path(s)`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-08-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-08-01T18:24:40.491Z",
|
|
5
|
+
"instarVersion": "1.3.1103",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedFrom": "source-tree",
|
|
4
4
|
"registrySha256": "5413a0c6ef9ba2bda876b509d1c0bfebe450da3708cd5a5d627d6cb836012d58",
|
|
5
|
-
"packageVersion": "1.3.
|
|
5
|
+
"packageVersion": "1.3.1103",
|
|
6
6
|
"guards": [
|
|
7
7
|
{
|
|
8
8
|
"ref": "docs/canonical-migration-contracts.json",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sha256": "
|
|
2
|
+
"sha256": "134f316424c9c178f1e9512d39504d10c88e6fad36e013596f2e25cff658488f",
|
|
3
3
|
"registrySha256": "5413a0c6ef9ba2bda876b509d1c0bfebe450da3708cd5a5d627d6cb836012d58",
|
|
4
|
-
"packageVersion": "1.3.
|
|
4
|
+
"packageVersion": "1.3.1103"
|
|
5
5
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
`scripts/ux-impact-lint.mjs` decides whether a PR counts as user-facing by matching
|
|
9
|
+
changed files against a hard-coded allowlist. That allowlist omitted
|
|
10
|
+
`src/scaffold/templates.ts` — the file the Agent Awareness Standard names as THE
|
|
11
|
+
user-awareness surface ("An agent that doesn't know about a capability effectively
|
|
12
|
+
doesn't have it"). A PR touching only that file matched nothing, hit
|
|
13
|
+
`allowlisted.length === 0`, and exited 0. The change that alters what every agent tells
|
|
14
|
+
its users required no UX declaration at all. `src/templates/` (hook and helper scripts)
|
|
15
|
+
was allowlisted; `src/scaffold/` was not.
|
|
16
|
+
|
|
17
|
+
Three edits, one defect:
|
|
18
|
+
|
|
19
|
+
1. The `:25` allowlist gains `p === 'src/scaffold/templates.ts'` — the exact file the
|
|
20
|
+
standard names, in the exact exact-match style already used for two other files.
|
|
21
|
+
Deliberately **not** `startsWith('src/scaffold/')`: widening a gate beyond what a
|
|
22
|
+
standard names is a policy change nobody approved.
|
|
23
|
+
2. The `:30` refactor-only exemption excludes that path too — rewriting agent-visible
|
|
24
|
+
text is never a pure refactor.
|
|
25
|
+
3. The `:41` failure message now names the concept and lists the paths actually
|
|
26
|
+
searched. It previously read "UX Impact must quote a concrete string from the diff"
|
|
27
|
+
while searching only the allowlisted subset of the diff, so an author who correctly
|
|
28
|
+
quoted a real added line from an unlisted file was told something untrue about why
|
|
29
|
+
they failed.
|
|
30
|
+
|
|
31
|
+
The gating predicate at `:40` is untouched. `scripts/` is CI-only, is not bundled into
|
|
32
|
+
`dist/`, and is executed by no deployed agent, so no running agent's behaviour changes.
|
|
33
|
+
|
|
34
|
+
## What to Tell Your User
|
|
35
|
+
|
|
36
|
+
None — internal change (no user-facing surface).
|
|
37
|
+
|
|
38
|
+
## Summary of New Capabilities
|
|
39
|
+
|
|
40
|
+
None — internal change (no user-facing surface).
|
|
41
|
+
|
|
42
|
+
## Evidence
|
|
43
|
+
|
|
44
|
+
Verified against real commit `e29259c49`, which touches `src/scaffold/templates.ts` and
|
|
45
|
+
zero allowlisted paths (both confirmed by control counts):
|
|
46
|
+
|
|
47
|
+
| lint | result |
|
|
48
|
+
|---|---|
|
|
49
|
+
| shipping (`origin/main`) | `UX lint: out of scope`, exit 0 — gate skipped entirely |
|
|
50
|
+
| patched | engages, exit 1 on `UX-Impact: none` |
|
|
51
|
+
| patched, replaying PR #1813 | exit 0 — no regression on a real passing PR |
|
|
52
|
+
|
|
53
|
+
The static contradiction, with a control: `CLAUDE.md` names `src/scaffold/templates.ts`
|
|
54
|
+
as the user-awareness surface, while `ux-impact-lint.mjs` contained `scaffold` zero
|
|
55
|
+
times (control: `templates` = 2, so the search works and this is a true negative).
|
|
56
|
+
|
|
57
|
+
New test `tests/unit/ux-impact-lint-scaffold-scope.test.ts` covers both sides of the
|
|
58
|
+
boundary and was trip-tested by reverting the lint to `origin/main`: 3/3 pass with the
|
|
59
|
+
fix, 2 fail without it, and the internal-path control passes either way.
|
|
60
|
+
|
|
61
|
+
Known residual, not claimed as fixed: the allowlist remains a proxy for "user-facing"
|
|
62
|
+
and still omits `PostUpdateMigrator.ts`, skill bodies, and hook templates. This closes
|
|
63
|
+
one hole in one list; the list still has no owner and no review trigger.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Side-Effects Review — UX-impact gate: recognise `src/scaffold/templates.ts` as a user-facing path
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `ux-gate-scaffold-scope`
|
|
4
|
+
**Date:** `2026-08-01`
|
|
5
|
+
**Author:** `Echo (instar-dev)`
|
|
6
|
+
**Second-pass reviewer:** `REQUIRED — this change modifies a gate` (see §Second pass)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
`scripts/ux-impact-lint.mjs` decides whether a PR is "user-facing" by matching changed
|
|
11
|
+
files against a hard-coded allowlist (`:25`). That allowlist omitted
|
|
12
|
+
`src/scaffold/templates.ts` — the file the Agent Awareness Standard names as THE
|
|
13
|
+
user-awareness surface ("An agent that doesn't know about a capability effectively
|
|
14
|
+
doesn't have it"). A PR touching only that file therefore hit `allowlisted.length === 0`
|
|
15
|
+
(`:27`) and exited 0, requiring no UX declaration for the change that alters what every
|
|
16
|
+
agent tells its users. Three edits, one defect: the path joins the allowlist (`:25`), it
|
|
17
|
+
also disqualifies the refactor-only exemption (`:30`), and the quote-check failure message
|
|
18
|
+
(`:41`) now names the concept and lists the paths actually searched. Adds
|
|
19
|
+
`tests/unit/ux-impact-lint-scaffold-scope.test.ts`.
|
|
20
|
+
|
|
21
|
+
## Decision-point inventory
|
|
22
|
+
|
|
23
|
+
- `ux-impact-lint.mjs:25` — **modify** — allowlist membership; adds one exact-match path.
|
|
24
|
+
- `ux-impact-lint.mjs:27` — **pass-through** — the in-scope/out-of-scope exit. Unchanged
|
|
25
|
+
logic; a strictly smaller set of PRs now reaches the `exit(0)` skip.
|
|
26
|
+
- `ux-impact-lint.mjs:30` — **modify** — refactor-only exemption eligibility.
|
|
27
|
+
- `ux-impact-lint.mjs:41` — **modify** — failure MESSAGE only. The predicate at `:40` is
|
|
28
|
+
untouched.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 1. Over-block
|
|
33
|
+
|
|
34
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
35
|
+
|
|
36
|
+
A PR that touches `src/scaffold/templates.ts` for a genuinely non-user-visible reason —
|
|
37
|
+
e.g. renaming a local variable inside `generateClaudeMd()`, or reflowing a comment — now
|
|
38
|
+
requires a UX Impact section where previously it required none. That is a real new cost
|
|
39
|
+
imposed on a legitimate input.
|
|
40
|
+
|
|
41
|
+
Two mitigations, both pre-existing: the `refactor-only` exemption still applies when the
|
|
42
|
+
change adds no quoted strings (`:31`), and the author can satisfy the gate by quoting any
|
|
43
|
+
concrete added string. It is a friction increase, not a wall. Concretely: a
|
|
44
|
+
whitespace-only change to that file will now demand a declaration, which is mildly
|
|
45
|
+
annoying and is the price of the file being in scope at all.
|
|
46
|
+
|
|
47
|
+
## 2. Under-block
|
|
48
|
+
|
|
49
|
+
**What failure modes does this still miss?**
|
|
50
|
+
|
|
51
|
+
Substantially more than it catches, and this must not be oversold:
|
|
52
|
+
|
|
53
|
+
- The allowlist remains a **proxy** for "user-facing" and still omits every other path
|
|
54
|
+
that can reach a user — `src/core/PostUpdateMigrator.ts` (which writes agent-visible
|
|
55
|
+
guidance on upgrade), skill `SKILL.md` bodies, `src/data/http-hook-templates.ts`, and
|
|
56
|
+
any future file that renders text a human reads.
|
|
57
|
+
- The gate only fires on **PR paths**, so a user-visible change delivered by a config
|
|
58
|
+
default or a runtime string has no coverage here at all.
|
|
59
|
+
- A PR touching `src/scaffold/templates.ts` **and** an already-allowlisted file was
|
|
60
|
+
already in scope, so for that (common) shape this change alters nothing.
|
|
61
|
+
- The quote check is satisfied by ANY quoted substring present in the allowlisted diff.
|
|
62
|
+
An author can still quote something trivially true and unrelated to the actual user
|
|
63
|
+
impact. This change does not make declarations honest; it makes them required.
|
|
64
|
+
|
|
65
|
+
## 3. Level-of-abstraction fit
|
|
66
|
+
|
|
67
|
+
The fix operates at the same level as the defect: a path missing from a path list is
|
|
68
|
+
repaired by adding the path. No new abstraction, no new config surface, no new file.
|
|
69
|
+
The alternative — deriving "user-facing" from something semantic rather than a path list
|
|
70
|
+
— would be a genuinely better design and is deliberately NOT attempted here; it is a
|
|
71
|
+
redesign, not a fix, and would ship as its own spec.
|
|
72
|
+
|
|
73
|
+
## 4. Signal vs authority compliance
|
|
74
|
+
|
|
75
|
+
The gate is an **authority** (it exits non-zero and blocks a PR), and it stays exactly as
|
|
76
|
+
authoritative as it was — the change alters WHICH files it considers, never WHETHER it
|
|
77
|
+
may block. No new authority is created. The message change at `:41` is pure signal
|
|
78
|
+
improvement and carries no gating weight.
|
|
79
|
+
|
|
80
|
+
Notably this change does not grant the gate any new power over anything outside the repo,
|
|
81
|
+
and it cannot affect a running agent: `scripts/` is CI-only and ships in no runtime path.
|
|
82
|
+
|
|
83
|
+
## 4b. Judgment-point check (Judgment Within Floors standard)
|
|
84
|
+
|
|
85
|
+
No judgment point is added. Every predicate is deterministic string matching; there is no
|
|
86
|
+
LLM call, no heuristic, and no scoring. The one judgment exercised was authorial and is
|
|
87
|
+
recorded here: **exact-match `src/scaffold/templates.ts` rather than
|
|
88
|
+
`startsWith('src/scaffold/')`**, because the standard names one file and widening a gate
|
|
89
|
+
beyond what a standard names is a policy change no one approved.
|
|
90
|
+
|
|
91
|
+
## 5. Interactions
|
|
92
|
+
|
|
93
|
+
- **`.github/workflows/ux-impact-pr-gate.yml`** — unchanged. Its `paths:` trigger already
|
|
94
|
+
includes `scripts/ux-impact-lint.mjs`, so the workflow's own trigger set needs no edit.
|
|
95
|
+
- **Agent Awareness Standard (CLAUDE.md)** — this change makes the gate agree with the
|
|
96
|
+
standard rather than contradict it. Nothing else consumes the allowlist.
|
|
97
|
+
- **`report.allowlistedPaths`** (`:26`) — the emitted JSON report may now contain one more
|
|
98
|
+
path. Any downstream consumer reading that array sees a longer list; no consumer in this
|
|
99
|
+
repo branches on its contents.
|
|
100
|
+
- **No interaction with the release pipeline, migrations, or PostUpdateMigrator.**
|
|
101
|
+
|
|
102
|
+
## 6. External surfaces
|
|
103
|
+
|
|
104
|
+
None. `scripts/ux-impact-lint.mjs` runs only in CI, is not bundled into `dist/`, is not
|
|
105
|
+
served by any route, and is never executed by a deployed agent. No API, no dashboard, no
|
|
106
|
+
Telegram surface, no config key. The only humans who observe a behaviour change are
|
|
107
|
+
contributors opening PRs against this repo.
|
|
108
|
+
|
|
109
|
+
## 6b. Operator-surface quality (Operator-Surface Quality standard)
|
|
110
|
+
|
|
111
|
+
The operator-visible surface is the CI failure message, and this change exists partly to
|
|
112
|
+
improve it. Before: `UX Impact must quote a concrete string from the diff` — which is
|
|
113
|
+
misleading, because the script searches only the allowlisted subset of the diff, so an
|
|
114
|
+
author quoting a genuine added line from an unlisted file is told something false about
|
|
115
|
+
why they failed. After: the message names the concept ("the USER-FACING paths this PR
|
|
116
|
+
touches"), enumerates those paths, and states plainly that quotes from other changed files
|
|
117
|
+
are not checked. An author can now self-diagnose in one read.
|
|
118
|
+
|
|
119
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
120
|
+
|
|
121
|
+
Not applicable. CI-only script with no state, no lease interaction, no replication, and no
|
|
122
|
+
per-machine behaviour. It executes once per workflow run on a GitHub runner.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Risks accepted
|
|
127
|
+
|
|
128
|
+
1. **Friction on incidental edits** to `src/scaffold/templates.ts` (§1). Accepted: the
|
|
129
|
+
file's whole purpose is agent-visible text, so incidental edits are rare and a
|
|
130
|
+
declaration is cheap.
|
|
131
|
+
2. **The proxy remains a proxy** (§2). Accepted for this change and explicitly NOT claimed
|
|
132
|
+
as fixed. The allowlist still has no owner and no review trigger; that is a real
|
|
133
|
+
residual and is stated in the ELI16 rather than hidden.
|
|
134
|
+
|
|
135
|
+
## Evidence
|
|
136
|
+
|
|
137
|
+
Verified against real commit `e29259c49` (touches `src/scaffold/templates.ts`, zero
|
|
138
|
+
allowlisted paths — both confirmed by control counts):
|
|
139
|
+
|
|
140
|
+
| lint | result |
|
|
141
|
+
|---|---|
|
|
142
|
+
| shipping (`origin/main`) | `UX lint: out of scope`, **exit 0** — gate skipped |
|
|
143
|
+
| patched | engages, **exit 1** on `UX-Impact: none` |
|
|
144
|
+
| patched, replaying PR #1813 | **exit 0** — no regression on a real passing PR |
|
|
145
|
+
|
|
146
|
+
Tests trip-tested in both directions: **3/3 pass** with the fix; **2 fail** without it;
|
|
147
|
+
the internal-path control passes either way (as a control must).
|
|
148
|
+
|
|
149
|
+
## Second pass
|
|
150
|
+
|
|
151
|
+
This change modifies a **gate**, which mandates second-pass review. Requested from Codey
|
|
152
|
+
on the PR. Not self-certified: the reviewer's response will be appended here.
|