@seasonkoh/webaz 0.1.19 → 0.1.21
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/layer0-foundation/L0-2-state-machine/engine.js +165 -26
- package/dist/layer0-foundation/L0-2-state-machine/order-chain.js +23 -0
- package/dist/layer0-foundation/L0-2-state-machine/transitions.js +65 -2
- package/dist/layer1-agent/L1-1-mcp-server/server.js +38 -27
- package/dist/layer2-business/L2-8-feedback/build-feedback-engine.js +34 -4
- package/dist/pwa/contract-fingerprint.js +46 -0
- package/dist/pwa/economic-participation.js +122 -0
- package/dist/pwa/endpoint-actions.js +112 -0
- package/dist/pwa/entity-dictionary.js +125 -0
- package/dist/pwa/goal-index.js +60 -0
- package/dist/pwa/integration-contract.js +64 -0
- package/dist/pwa/limits.js +30 -0
- package/dist/pwa/negative-space.js +64 -0
- package/dist/pwa/public/app.js +52 -47
- package/dist/pwa/public/docs/ECONOMIC-MODEL.md +287 -0
- package/dist/pwa/public/docs/INTEGRATOR.md +67 -0
- package/dist/pwa/public/docs/META-RULES-FULL.md +543 -0
- package/dist/pwa/public/i18n.js +44 -41
- package/dist/pwa/routes/disputes-write.js +68 -0
- package/dist/pwa/routes/orders-action.js +93 -1
- package/dist/pwa/routes/orders-read.js +18 -0
- package/dist/pwa/routes/public-utils.js +131 -1
- package/dist/pwa/routes/webauthn.js +9 -1
- package/dist/pwa/server.js +32 -121
- package/dist/pwa/verifiability-index.js +63 -0
- package/dist/version.js +32 -0
- package/package.json +2 -1
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { SOFTWARE_VERSION, CONTRACT_VERSION } from '../../version.js';
|
|
5
|
+
import { capabilityMatrix } from '../endpoint-actions.js';
|
|
6
|
+
import { buildEntityDictionary } from '../entity-dictionary.js';
|
|
7
|
+
import { buildGoalIndex } from '../goal-index.js';
|
|
8
|
+
import { buildChangeFeed } from '../contract-fingerprint.js';
|
|
9
|
+
import { buildIntegrationContract } from '../integration-contract.js';
|
|
10
|
+
import { buildVerifiabilityIndex } from '../verifiability-index.js';
|
|
11
|
+
import { buildEconomicParticipation } from '../economic-participation.js';
|
|
12
|
+
import { buildNegativeSpace } from '../negative-space.js';
|
|
1
13
|
export function registerPublicUtilsRoutes(app, deps) {
|
|
2
14
|
const { db, MASTER_SEED, NODE_ENV, SERVICE_START_MS, rateLimitOk, generateManifest, getUser, logError, issuerAddress } = deps;
|
|
3
15
|
app.get('/api/health', (_req, res) => {
|
|
@@ -73,7 +85,11 @@ export function registerPublicUtilsRoutes(app, deps) {
|
|
|
73
85
|
const issuerActiveSince = db.prepare("SELECT value FROM system_state WHERE key='issuer_active_since'").get()?.value || '2026-05-30';
|
|
74
86
|
return {
|
|
75
87
|
name: 'WebAZ Protocol',
|
|
76
|
-
|
|
88
|
+
// RFC-011 §④ 两轴版本(单一来源 src/version.ts):
|
|
89
|
+
// schema_version = 集成契约版本(整数,仅 breaking 契约变更才 bump;集成方 agent 按此判兼容)
|
|
90
|
+
// software_version = 本代码 npm/release semver(= package.json,自动同步,永不漂移)
|
|
91
|
+
schema_version: CONTRACT_VERSION,
|
|
92
|
+
software_version: SOFTWARE_VERSION,
|
|
77
93
|
network_state: {
|
|
78
94
|
phase,
|
|
79
95
|
real_users_on_canonical: realUsers,
|
|
@@ -106,6 +122,22 @@ export function registerPublicUtilsRoutes(app, deps) {
|
|
|
106
122
|
agent_governance: 'https://github.com/seasonsagents-art/webaz/blob/main/docs/AGENT-GOVERNANCE.md',
|
|
107
123
|
protocol_compatibility: 'https://github.com/seasonsagents-art/webaz/blob/main/docs/PROTOCOL-COMPATIBILITY-AUDIT-2026-05-30.md',
|
|
108
124
|
changelog: 'https://github.com/seasonsagents-art/webaz/blob/main/CHANGELOG.md',
|
|
125
|
+
// RFC-011 §②:agent 可读能力矩阵(写边界 action-scope + 敏感读 scope),live doc=code
|
|
126
|
+
capability_matrix: 'https://webaz.xyz/.well-known/webaz-capabilities.json',
|
|
127
|
+
},
|
|
128
|
+
// RFC-011 agent 接入 live 端点;总入口 integration.json 把它们按旅程串起来
|
|
129
|
+
agent_endpoints: {
|
|
130
|
+
integration_contract: 'https://webaz.xyz/.well-known/webaz-integration.json', // RFC-011 总入口(按旅程导航全维度)
|
|
131
|
+
capability_matrix: 'https://webaz.xyz/.well-known/webaz-capabilities.json', // ② 边界(#126)
|
|
132
|
+
entity_dictionary: 'https://webaz.xyz/.well-known/webaz-entities.json', // ① 语义(order/product/dispute 状态机 + 字段)
|
|
133
|
+
goal_index: 'https://webaz.xyz/.well-known/webaz-goals.json', // ① 目标索引(intent → action + endpoint + 工具)
|
|
134
|
+
change_feed: 'https://webaz.xyz/api/agent/changes', // ④ 契约变更 + 指纹 + 弃用
|
|
135
|
+
verifiability_index: 'https://webaz.xyz/.well-known/webaz-verifiability.json', // ⑤ 什么可验+怎么验
|
|
136
|
+
economic_participation: 'https://webaz.xyz/.well-known/webaz-economic.json', // ⑧ value-participant 角色经济条款(费率实时)
|
|
137
|
+
negative_space: 'https://webaz.xyz/.well-known/webaz-negative-space.json', // ② 负空间(禁区 + 限额 + 后果阶梯)
|
|
138
|
+
event_stream: 'https://webaz.xyz/api/agent/events?since=<cursor>', // ⑥ 事件游标流(party-gated,需 auth)
|
|
139
|
+
passport: 'https://webaz.xyz/api/me/agents/:apiKeyPrefix/passport', // ⑤ 可验护照
|
|
140
|
+
did: 'https://webaz.xyz/.well-known/did.json',
|
|
109
141
|
},
|
|
110
142
|
// 路线图 — 回应"知道还有哪些没做"的诚实化第三层。哲学:公开当前到达点 + 已知未做项,不承诺时间表。
|
|
111
143
|
roadmap: {
|
|
@@ -140,6 +172,104 @@ export function registerPublicUtilsRoutes(app, deps) {
|
|
|
140
172
|
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
141
173
|
res.json(buildProtocolManifest());
|
|
142
174
|
});
|
|
175
|
+
// RFC-011 §② — agent 可读能力矩阵(写边界 action-scope + 敏感读 scope)。
|
|
176
|
+
// live = 直接序列化 enforce 用的规则表(src/pwa/endpoint-actions.ts),doc=code 零漂移。
|
|
177
|
+
// 集成方 agent fetch 此端点即知"我要做的写需要声明哪个 scope / 哪些写无需 scope / 哪些读受约束"。
|
|
178
|
+
app.get('/.well-known/webaz-capabilities.json', (_req, res) => {
|
|
179
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
180
|
+
res.json(capabilityMatrix());
|
|
181
|
+
});
|
|
182
|
+
app.get('/api/agent/capabilities', (_req, res) => {
|
|
183
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
184
|
+
res.json(capabilityMatrix());
|
|
185
|
+
});
|
|
186
|
+
// RFC-011 §① — agent 可读实体字典(订单状态机 doc=code + 保守公开字段 + 可验证标注)。
|
|
187
|
+
app.get('/.well-known/webaz-entities.json', (_req, res) => {
|
|
188
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
189
|
+
res.json(buildEntityDictionary());
|
|
190
|
+
});
|
|
191
|
+
app.get('/api/agent/entities', (_req, res) => {
|
|
192
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
193
|
+
res.json(buildEntityDictionary());
|
|
194
|
+
});
|
|
195
|
+
// RFC-011 §① 目标索引 —— intent → action(②)+ endpoint + MCP 工具 + PWA 页(agent 自路由)。
|
|
196
|
+
app.get('/.well-known/webaz-goals.json', (_req, res) => {
|
|
197
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
198
|
+
res.json(buildGoalIndex());
|
|
199
|
+
});
|
|
200
|
+
// 集成必需文档(规则 + onboarding)由协议自身 serve —— 外部 agent 必须能读到约束它的规则,
|
|
201
|
+
// 不能指向私有 repo 的 GitHub(对外 404)。显式白名单:只暴露这 3 份"本就该公开"的文档,
|
|
202
|
+
// 非白名单 → 404(不泄漏 RFC/审计等内部设计文档;它们是 provenance,随 repo 公开解锁)。
|
|
203
|
+
const PUBLIC_DOCS = new Set(['INTEGRATOR.md', 'META-RULES-FULL.md', 'ECONOMIC-MODEL.md']);
|
|
204
|
+
const DOCS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../docs'); // repo-root/docs(dev+prod 都解析到此)
|
|
205
|
+
app.get('/docs/:name', (req, res) => {
|
|
206
|
+
const name = String(req.params.name);
|
|
207
|
+
if (!PUBLIC_DOCS.has(name))
|
|
208
|
+
return void res.status(404).json({ error: 'not a public doc', public_docs: [...PUBLIC_DOCS] });
|
|
209
|
+
try {
|
|
210
|
+
const md = readFileSync(path.join(DOCS_DIR, name), 'utf8');
|
|
211
|
+
res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
|
|
212
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
213
|
+
res.send(md);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
res.status(404).json({ error: 'doc unavailable' });
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
app.get('/api/agent/goals', (_req, res) => {
|
|
220
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
221
|
+
res.json(buildGoalIndex());
|
|
222
|
+
});
|
|
223
|
+
// RFC-011 §④ — 契约变更 feed:current_contract_version + 契约面指纹 + 变更注册表 + 弃用策略。
|
|
224
|
+
// agent 用上次见过的 contract_version poll;指纹让它不必 diff 整份契约就知道有没有漂移。
|
|
225
|
+
// 指纹由 tests/test-contract-fingerprint.ts + docs/CONTRACT-LOCK.json 守住(静默改契约不可 merge)。
|
|
226
|
+
app.get('/api/agent/changes', (_req, res) => {
|
|
227
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
228
|
+
res.json(buildChangeFeed());
|
|
229
|
+
});
|
|
230
|
+
// RFC-011 总入口 —— 集成方 agent 一次 fetch 拿到整份契约导航(按旅程组织,指向各维度 live 端点)。
|
|
231
|
+
app.get('/.well-known/webaz-integration.json', (_req, res) => {
|
|
232
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
233
|
+
res.json(buildIntegrationContract());
|
|
234
|
+
});
|
|
235
|
+
app.get('/api/agent/integration', (_req, res) => {
|
|
236
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
237
|
+
res.json(buildIntegrationContract());
|
|
238
|
+
});
|
|
239
|
+
// RFC-011 §⑤ 可验证索引 —— "什么可验 + 怎么验"统一表(护照/锚/AP2/订单链),诚实分级。
|
|
240
|
+
app.get('/.well-known/webaz-verifiability.json', (_req, res) => {
|
|
241
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
242
|
+
res.json(buildVerifiabilityIndex());
|
|
243
|
+
});
|
|
244
|
+
app.get('/api/agent/verifiability', (_req, res) => {
|
|
245
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
246
|
+
res.json(buildVerifiabilityIndex());
|
|
247
|
+
});
|
|
248
|
+
// RFC-011 §⑧ 经济参与索引 —— value-participant 角色 × 赚什么/押什么/担什么责,
|
|
249
|
+
// 费率【实时】从 protocol_params 读(doc=code,永不和 enforced 经济漂移)。
|
|
250
|
+
const liveParam = (key, fallback) => {
|
|
251
|
+
const row = db.prepare('SELECT value, type FROM protocol_params WHERE key = ?').get(key);
|
|
252
|
+
if (!row)
|
|
253
|
+
return fallback;
|
|
254
|
+
if (row.type === 'number')
|
|
255
|
+
return Number(row.value);
|
|
256
|
+
if (row.type === 'boolean')
|
|
257
|
+
return (row.value === 'true' || row.value === '1');
|
|
258
|
+
return row.value;
|
|
259
|
+
};
|
|
260
|
+
const economic = (_req, res) => {
|
|
261
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
262
|
+
res.json(buildEconomicParticipation(liveParam));
|
|
263
|
+
};
|
|
264
|
+
app.get('/.well-known/webaz-economic.json', economic);
|
|
265
|
+
app.get('/api/agent/economic-participation', economic);
|
|
266
|
+
// RFC-011 §② 负空间 —— 禁区 + enforced 限额 + 后果阶梯(per-agent 速率实时读)。
|
|
267
|
+
const negativeSpace = (_req, res) => {
|
|
268
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
269
|
+
res.json(buildNegativeSpace(liveParam));
|
|
270
|
+
};
|
|
271
|
+
app.get('/.well-known/webaz-negative-space.json', negativeSpace);
|
|
272
|
+
app.get('/api/agent/negative-space', negativeSpace);
|
|
143
273
|
// W3C DID Document(B.6 b DID 短期 mapping,2026-05-30):
|
|
144
274
|
// did:web:webaz.xyz 通过 HTTPS 解析到这里(W3C did:web spec §3.2)
|
|
145
275
|
// verificationMethod 用 EcdsaSecp256k1RecoveryMethod2020 + CAIP-10 blockchainAccountId
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { generateRegistrationOptions, verifyRegistrationResponse, generateAuthenticationOptions, verifyAuthenticationResponse, } from '@simplewebauthn/server';
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
|
+
// RFC-004 体验补:绑定 Passkey 后,追溯补发此前"已受理但无锚点跳过"的建设信誉。
|
|
4
|
+
import { grantPendingAnchorCredits } from '../../layer2-business/L2-8-feedback/build-feedback-engine.js';
|
|
3
5
|
export function registerWebauthnRoutes(app, deps) {
|
|
4
6
|
const { db, auth, generateId, rpId, rpName, origin, challengeTtlMs, gateTtlMs, invalidateAgentRiskCacheForUser, requireHumanPresence } = deps;
|
|
5
7
|
// 1. 注册:start — 生成 challenge + 选项
|
|
@@ -53,7 +55,13 @@ export function registerWebauthnRoutes(app, deps) {
|
|
|
53
55
|
.run(credential.id, user.id, Buffer.from(credential.publicKey), credential.counter || 0, JSON.stringify(credential.transports || []), (device_label || '').slice(0, 60) || null);
|
|
54
56
|
db.prepare("UPDATE webauthn_challenges SET consumed_at = datetime('now') WHERE id = ?").run(challenge_id);
|
|
55
57
|
invalidateAgentRiskCacheForUser(user.id); // 让 D2b 中间件立刻看到刚绑的 Passkey,否则 5min 缓存窗内仍被拦
|
|
56
|
-
|
|
58
|
+
// RFC-004:绑定 Passkey = 成为可问责真人 → 追溯补发此前因无锚点跳过的建设信誉(advisory,永不阻塞绑定)
|
|
59
|
+
let backfilled;
|
|
60
|
+
try {
|
|
61
|
+
backfilled = grantPendingAnchorCredits(db, user.id);
|
|
62
|
+
}
|
|
63
|
+
catch { /* 不影响绑定主流程 */ }
|
|
64
|
+
res.json({ success: true, credential_id: credential.id, ...(backfilled && backfilled.granted > 0 ? { build_credit_backfilled: backfilled } : {}) });
|
|
57
65
|
}
|
|
58
66
|
catch (e) {
|
|
59
67
|
res.status(400).json({ error: e.message });
|
package/dist/pwa/server.js
CHANGED
|
@@ -20,7 +20,9 @@ import path from 'path';
|
|
|
20
20
|
import { fileURLToPath } from 'url';
|
|
21
21
|
import crypto from 'crypto';
|
|
22
22
|
import { initDatabase, generateId } from '../layer0-foundation/L0-1-database/schema.js';
|
|
23
|
-
import { initSystemUser, transition, getOrderStatus, checkTimeouts } from '../layer0-foundation/L0-2-state-machine/engine.js';
|
|
23
|
+
import { initSystemUser, transition, getOrderStatus, checkTimeouts, settleFault } from '../layer0-foundation/L0-2-state-machine/engine.js';
|
|
24
|
+
import { endpointToAction, endpointToReadAction } from './endpoint-actions.js';
|
|
25
|
+
import { AGENT_RATE_PER_MIN_DEFAULTS, CROSS_USER_READ_DAILY_CAP, MASS_ACTION_TYPES, MASS_ACTION_DAILY_CAPS } from './limits.js';
|
|
24
26
|
import { initOrderChainSchema, appendOrderEvent, getOrderChain, verifyOrderChain } from '../layer0-foundation/L0-2-state-machine/order-chain.js';
|
|
25
27
|
import { initSnfSchema, snfSend, snfCleanup } from '../layer2-business/L2-7-snf/snf-engine.js';
|
|
26
28
|
import { initExternalAnchorSchema } from '../layer1-agent/L1-2-external-anchor/anchor-engine.js';
|
|
@@ -534,6 +536,15 @@ for (const stmt of [
|
|
|
534
536
|
// RFC-008 stage 1:每单【赔付背书】快照 = 该单实际背书的卖家质押额。
|
|
535
537
|
// 起步免赔付阶段(require_seller_stake=0)= 0;违约结算只按此数没收,绝不扣未背书的钱 → 根治印钱 bug。
|
|
536
538
|
'ALTER TABLE orders ADD COLUMN stake_backing REAL DEFAULT 0',
|
|
539
|
+
// RFC-007 stage 2:卖家【主动拒单】记录(vs 沉默超时)。reason_code 供 stage 3/5 判定客观/主观。
|
|
540
|
+
'ALTER TABLE orders ADD COLUMN decline_reason_code TEXT',
|
|
541
|
+
'ALTER TABLE orders ADD COLUMN declined_at TEXT',
|
|
542
|
+
// RFC-007 stage 3:客观理由拒单 → 【临时判责】(provisional)。先不结算,给卖家举证窗口(stage 5 仲裁翻案)。
|
|
543
|
+
// pending=1 + deadline 到期仍无人仲裁 → checkTimeouts 终结为违约(settleFault)。stage 5 仲裁维持则翻 declined_nofault。
|
|
544
|
+
'ALTER TABLE orders ADD COLUMN decline_objective_pending INTEGER DEFAULT 0',
|
|
545
|
+
'ALTER TABLE orders ADD COLUMN decline_contest_deadline TEXT',
|
|
546
|
+
// RFC-007 stage 5:卖家已就临时判责发起仲裁举证 → 暂停 checkTimeouts 自动终结,等人工仲裁裁决。
|
|
547
|
+
'ALTER TABLE orders ADD COLUMN decline_contested INTEGER DEFAULT 0',
|
|
537
548
|
]) {
|
|
538
549
|
try {
|
|
539
550
|
db.exec(stmt);
|
|
@@ -778,6 +789,13 @@ const DEFAULT_PARAMS = [
|
|
|
778
789
|
{ key: 'fund_base_rate', value: '0', type: 'number', description: '协议基金池基础费率(RFC-008 硬帽 1%;pre-launch 减免=0,有真实 GMV 再由治理开启 ≤1%)', category: 'fee', min: 0, max: 0.01 },
|
|
779
790
|
// RFC-008:起步免赔付门槛。0 = bootstrap(新商家零质押、违约免赔付只退款+掉信誉,降进入门槛);1 = 要求卖家质押(下单锁 stake、违约真没收)。上轨道后由治理开启。
|
|
780
791
|
{ key: 'require_seller_stake', value: '0', type: 'number', description: 'RFC-008 是否要求卖家质押(0=起步免赔付/零门槛,1=要求质押/真没收)', category: 'fee', min: 0, max: 1 },
|
|
792
|
+
// RFC-008 stage 2:违约罚没率,【与质押率解耦】(低质押=低摩擦 + 高罚没=强威慑,单一费率做不到)。
|
|
793
|
+
// 背书订单:penalty = fault_penalty_rate × total,先扣 staked(封顶背书)再扣自由 balance(责任自负,真可执行)。
|
|
794
|
+
// 起步免赔付(stake_backing=0):仍 0 没收,绝不碰新商家自由余额。settleFault 按订单 stake_backing 判定。
|
|
795
|
+
{ key: 'fault_penalty_rate', value: '0.30', type: 'number', description: 'RFC-008 违约罚没率(与质押率解耦;背书订单 staked 不足扣自由 balance;起步免赔付订单不适用)', category: 'fee', min: 0, max: 0.50 },
|
|
796
|
+
// RFC-007 stage 3:客观理由拒单的【举证窗口】小时数。卖家声称客观无责拒单 → 临时判责,此窗口内可开仲裁(stage 5)举证;
|
|
797
|
+
// 到期无人仲裁 → 自动终结为违约。窗口内买家 escrow 暂不退(随终结/翻案一次性结算),0=不给窗口(直接违约)。
|
|
798
|
+
{ key: 'decline_contest_window_hours', value: '24', type: 'number', description: 'RFC-007 客观拒单举证窗口(小时);到期未仲裁则终结为违约', category: 'limit', min: 0, max: 168 },
|
|
781
799
|
{ key: 'checkin_base_reward', value: '0.5', type: 'number', description: '每日签到基础奖励 WAZ', category: 'reward', min: 0, max: 10 },
|
|
782
800
|
{ key: 'streak_bonus_7', value: '5', type: 'number', description: '7 天里程碑额外奖励', category: 'reward', min: 0, max: 100 },
|
|
783
801
|
{ key: 'streak_bonus_30', value: '20', type: 'number', description: '30 天里程碑额外奖励', category: 'reward', min: 0, max: 500 },
|
|
@@ -5160,23 +5178,19 @@ function issueAgentStrike(opts) {
|
|
|
5160
5178
|
void issueAgentStrike;
|
|
5161
5179
|
function getAgentRateCap(level) {
|
|
5162
5180
|
const key = `agent_rate_${level}_per_min`;
|
|
5163
|
-
return Number(getProtocolParam(key, level
|
|
5181
|
+
return Number(getProtocolParam(key, AGENT_RATE_PER_MIN_DEFAULTS[level] ?? AGENT_RATE_PER_MIN_DEFAULTS.new));
|
|
5164
5182
|
}
|
|
5165
5183
|
// 2026-05-23 P1 fix 2.4:mass-action 日 cap(按 trust level + action 类别)
|
|
5166
5184
|
// 拦截 spam / 信息轰炸:chat / comment / share 三类 social-write 操作有独立的日上限
|
|
5167
5185
|
// 触发:超 cap → 429 AGENT_DAILY_CAP;累计 ≥3 次超限 / 24h → issueAgentStrike(warning)
|
|
5168
|
-
|
|
5169
|
-
const
|
|
5170
|
-
|
|
5171
|
-
chat: { new: 30, trusted: 100, quality: 300, legend: 1000 },
|
|
5172
|
-
comment: { new: 20, trusted: 60, quality: 150, legend: 500 },
|
|
5173
|
-
share: { new: 10, trusted: 30, quality: 100, legend: 300 },
|
|
5174
|
-
};
|
|
5186
|
+
// 限额表抽到 ./limits.ts(单一真相源,与 RFC-011 §② negative-space 发布面共享)。
|
|
5187
|
+
const MASS_ACTION_TYPES_SET = new Set(MASS_ACTION_TYPES);
|
|
5188
|
+
const massActionDailyCaps = MASS_ACTION_DAILY_CAPS;
|
|
5175
5189
|
// in-memory 日窗口 counter(不持久化,重启清零;持久化需求未来用 agent_call_log 算)
|
|
5176
5190
|
const massActionDailyBuckets = new Map();
|
|
5177
5191
|
function todayKey() { return new Date().toISOString().slice(0, 10); }
|
|
5178
5192
|
function checkMassActionCap(apiKey, action, level) {
|
|
5179
|
-
if (!
|
|
5193
|
+
if (!MASS_ACTION_TYPES_SET.has(action))
|
|
5180
5194
|
return { ok: true };
|
|
5181
5195
|
const cap = (massActionDailyCaps[action] || {})[level] ?? massActionDailyCaps[action]?.new ?? 999999;
|
|
5182
5196
|
const today = todayKey();
|
|
@@ -5207,13 +5221,7 @@ function checkMassActionCap(apiKey, action, level) {
|
|
|
5207
5221
|
// · 防"枚举/扒数据"型读取(剽窃 / 内容农场 / 用户画像批量化)
|
|
5208
5222
|
// · 真人监护人(绑 Passkey) 也罩:audit "补 A" — 之前 Passkey 真人无任何 read cap,scraper 拿真人账号即绕过
|
|
5209
5223
|
// · 不打 /api/nearby /api/search(地理聚合 / 关键词查),那些已被 B1 read-scope 约束
|
|
5210
|
-
|
|
5211
|
-
passkey_human: 300, // 真人监护人 — 高但有上限(每天看 300 个不同用户已属异常使用)
|
|
5212
|
-
legend: 200, // 高信誉 agent
|
|
5213
|
-
quality: 100,
|
|
5214
|
-
trusted: 60,
|
|
5215
|
-
new: 30, // 新 agent — 30 个就该有声誉再说
|
|
5216
|
-
};
|
|
5224
|
+
// CROSS_USER_READ_DAILY_CAP 抽到 ./limits.ts(单一真相源)。
|
|
5217
5225
|
const crossUserReadBuckets = new Map();
|
|
5218
5226
|
function extractCrossUserTarget(path, currentUserId) {
|
|
5219
5227
|
// /api/users/:id 或 /api/users/:id/anything → :id;同 user 不算跨;sys_* 协议账号不算
|
|
@@ -5248,107 +5256,10 @@ function checkCrossUserReadCap(userId, targetId, level) {
|
|
|
5248
5256
|
}
|
|
5249
5257
|
// 2026-05-23 P0 audit fix 2.2:endpoint → action 映射(用于 declared_scope enforcement)
|
|
5250
5258
|
// 只对写操作 enforce;读操作不限制(任何 agent 都能读自己范围内的数据)
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
return 'place_order';
|
|
5256
|
-
if ((method === 'POST' || method === 'PUT') && /^\/api\/products(\/[^/]+)?$/.test(path))
|
|
5257
|
-
return 'list_product';
|
|
5258
|
-
if (method === 'POST' && /^\/api\/orders\/[^/]+\/(accept|ship|deliver|pickup|transit)/.test(path))
|
|
5259
|
-
return 'fulfill';
|
|
5260
|
-
if (method === 'POST' && /^\/api\/orders\/[^/]+\/confirm/.test(path))
|
|
5261
|
-
return 'confirm_order';
|
|
5262
|
-
if (method === 'POST' && /^\/api\/claim-tasks\/[^/]+\/vote/.test(path))
|
|
5263
|
-
return 'vote';
|
|
5264
|
-
if (method === 'POST' && /^\/api\/disputes\/[^/]+\/arbitrate/.test(path))
|
|
5265
|
-
return 'arbitrate';
|
|
5266
|
-
if (method === 'POST' && /^\/api\/disputes\/[^/]+\/respond/.test(path))
|
|
5267
|
-
return 'dispute_respond';
|
|
5268
|
-
if (method === 'POST' && /^\/api\/charity\/fund\/donate/.test(path))
|
|
5269
|
-
return 'donate';
|
|
5270
|
-
if (method === 'POST' && /^\/api\/(wishes|charity)/.test(path))
|
|
5271
|
-
return 'charity';
|
|
5272
|
-
if (method === 'POST' && /^\/api\/shareables/.test(path))
|
|
5273
|
-
return 'share';
|
|
5274
|
-
if (method === 'POST' && /^\/api\/conversations/.test(path))
|
|
5275
|
-
return 'chat';
|
|
5276
|
-
if (method === 'POST' && path === '/api/skills')
|
|
5277
|
-
return 'list_skill';
|
|
5278
|
-
if (method === 'POST' && /^\/api\/rfqs/.test(path))
|
|
5279
|
-
return 'rfq';
|
|
5280
|
-
if (method === 'POST' && /^\/api\/auctions\/[^/]+\/bid/.test(path))
|
|
5281
|
-
return 'bid';
|
|
5282
|
-
// 权限审计 #1115 P0:花钱/价值写纳入问责门(与 place_order 同档:无 Passkey 须声明 scope)。
|
|
5283
|
-
// 之前这些漏在 default-allow 之外,无声明无 Passkey 的 agent 可花掉账户余额 —— 补齐一致性。
|
|
5284
|
-
if (method === 'POST' && /^\/api\/skill-market\/[^/]+\/purchase/.test(path))
|
|
5285
|
-
return 'purchase';
|
|
5286
|
-
if (method === 'POST' && /^\/api\/secondhand\/[^/]+\/order/.test(path))
|
|
5287
|
-
return 'buy_secondhand';
|
|
5288
|
-
if (method === 'POST' && /^\/api\/group-buys\/[^/]+\/join/.test(path))
|
|
5289
|
-
return 'group_buy_join';
|
|
5290
|
-
// #1115 P1:写 PII(收货地址)也需问责。含 addresses 增删改 + profile 默认地址。
|
|
5291
|
-
if (method !== 'GET' && (/^\/api\/addresses(\/|$)/.test(path) || path === '/api/profile/default-address'))
|
|
5292
|
-
return 'set_address';
|
|
5293
|
-
// #1115 P2:钱包写(转出/充值/白名单/连接)统一纳入 'wallet' 问责门。
|
|
5294
|
-
// 之前 wallet/* 整段在 SAFE 放行 → api_key agent 可直达 withdraw,小额零真人门分批盗刷;
|
|
5295
|
-
// 现要求声明 'wallet' scope(或 '*' / Passkey)。withdraw 另在 handler 内强制 Passkey 真人门(铁律,见 wallet-write.ts)。
|
|
5296
|
-
if (method !== 'GET' && /^\/api\/wallet\//.test(path))
|
|
5297
|
-
return 'wallet';
|
|
5298
|
-
// #1115 P2:profile **PII/身份/接管向量**写纳入 'set_profile' —— 仅这一子集需问责。
|
|
5299
|
-
// 改恢复邮箱(bind/confirm-email)=账户接管;改 handle/name=身份;set/clear-location=地理 PII。
|
|
5300
|
-
// ⚠️ 不一刀切整段 profile/*:role/region/placement/password/verify 是"无 Passkey 也要能用"的
|
|
5301
|
-
// 自助操作(见原则:没身份验证也要解决的问题不要求身份),它们留在下方 SAFE。
|
|
5302
|
-
// default-address 已在上面归 set_address(更具体,优先)。
|
|
5303
|
-
if (method !== 'GET' && /^\/api\/profile\/(bind-email|confirm-email|change-handle|change-name|set-location|clear-location)$/.test(path))
|
|
5304
|
-
return 'set_profile';
|
|
5305
|
-
// ── #1115 B4 结构性:default-deny ──────────────────────────────
|
|
5306
|
-
// 上面是细粒度命名 token;下面 safe-list 放行(返回 null),其余一切写 → 'write'(需 Passkey 或声明 scope)。
|
|
5307
|
-
// 目的:新增的敏感写默认就被门控,不会因"忘了加映射"而裸奔(把 default-allow 翻成 default-deny)。
|
|
5308
|
-
// safe-list 三类必须放行(否则误伤 / 死锁):
|
|
5309
|
-
// (a) 脱困入口:绑 Passkey(webauthn)/ 声明 scope(me/agents)/ 登录注册/找回 —— 若门控则永远无法获得通行资格
|
|
5310
|
-
// (b) 自带门:build-feedback(分级门)/ admin(requireAdmin)。
|
|
5311
|
-
// 注意:wallet / profile 不再 SAFE —— #1115 P2 移到上方命名 token(wallet / set_profile / set_address)。
|
|
5312
|
-
// (c) 公开 + 低值自我状态写(管理自己的 cart/wishlist/通知/关注 等,登录即可)
|
|
5313
|
-
const SAFE = [
|
|
5314
|
-
// (a) 脱困 / 鉴权 / 身份(bootstrap 通行资格所必需 —— wallet 与 profile 的 PII 子集不在此列,见上方命名 token)
|
|
5315
|
-
/^\/api\/(login|register)$/, /^\/api\/recover-key/, /^\/api\/webauthn\//,
|
|
5316
|
-
/^\/api\/me\/agents\//,
|
|
5317
|
-
// profile 自助子集(无 Passkey 真人也要能用:切角色/选地区/PV 配置/改密码/二次确认)。
|
|
5318
|
-
// PII/身份子集(bind-email/change-handle/set-location 等)已在上方归 set_profile,不在此放行。
|
|
5319
|
-
/^\/api\/profile\/(switch-role|add-role|region|placement-pref|bind-placement|feed-visible|verify-password|set-password|remove-password)$/,
|
|
5320
|
-
// (b) 自带门(build-feedback=分级门;build-tasks=协调层登录即可;admin=requireAdmin。wallet/profile 已移到上方命名 token #1115 P2)
|
|
5321
|
-
/^\/api\/build-feedback/, /^\/api\/build-tasks/, /^\/api\/admin\//,
|
|
5322
|
-
// (c) 公开 / 无需登录
|
|
5323
|
-
/^\/api\/(public-ideas|error-report|mcp-telemetry|email-subscriptions|search-by-link|feedback)(\/|$)/,
|
|
5324
|
-
// (c) 低值自我状态
|
|
5325
|
-
/^\/api\/cart$/, /^\/api\/cart\/(?!checkout)[^/]+$/,
|
|
5326
|
-
/^\/api\/wishlist/, /^\/api\/products\/[^/]+\/waitlist$/,
|
|
5327
|
-
/^\/api\/notifications\/read$/, /^\/api\/announcements\/[^/]+\/read$/,
|
|
5328
|
-
/^\/api\/follows\//, /^\/api\/blocklist\//,
|
|
5329
|
-
/^\/api\/checkin$/, /^\/api\/growth\/tasks\//, /^\/api\/tasks\/[^/]+\/claim$/,
|
|
5330
|
-
/^\/api\/push\//, /^\/api\/auth\//,
|
|
5331
|
-
/^\/api\/me\/(delete-cancel|notify-claim-tasks)/,
|
|
5332
|
-
/^\/api\/peers\//, /^\/api\/signaling\//,
|
|
5333
|
-
/^\/api\/product-share\/touch$/, /^\/api\/anchor\/[^/]+\/touch$/,
|
|
5334
|
-
/^\/api\/reviews\//,
|
|
5335
|
-
];
|
|
5336
|
-
if (SAFE.some(r => r.test(path)))
|
|
5337
|
-
return null;
|
|
5338
|
-
return 'write'; // 默认拒绝:其余写需问责
|
|
5339
|
-
}
|
|
5340
|
-
// Phase 3b(B1):敏感读 → read-scope token 映射。只挑「跨用户聚合 / 批量扫描」这类剽窃向读取,
|
|
5341
|
-
// 普通读(自己的 profile / products 列表 / 订单等)一律 null 不约束,避免误伤声明 agent 的日常读。
|
|
5342
|
-
// 仅对「有声明」的 agent 生效(见中间件);真人 / 无声明 / 通配 '*' 都不受此约束。
|
|
5343
|
-
function endpointToReadAction(path) {
|
|
5344
|
-
if (/^\/api\/nearby/.test(path))
|
|
5345
|
-
return 'search'; // 雷达扫描(地理聚合)
|
|
5346
|
-
if (/^\/api\/search/.test(path))
|
|
5347
|
-
return 'search'; // 模糊搜索深翻页
|
|
5348
|
-
if (/^\/api\/users\/[^/]+\//.test(path))
|
|
5349
|
-
return 'profile'; // 他人主页 / 信誉 / 内容流(枚举剽窃向)
|
|
5350
|
-
return null;
|
|
5351
|
-
}
|
|
5259
|
+
// RFC-011 §②:写边界分类器 + 敏感读 scope 已抽到 src/pwa/endpoint-actions.ts(声明式规则表,
|
|
5260
|
+
// 同一份规则既 enforce(此处中间件迭代)又 publish(capabilityMatrix 端点),doc=code。
|
|
5261
|
+
// 行为零变化由 tests/test-endpoint-actions.ts 锁定(420 组 path×method diff legacy)。
|
|
5262
|
+
// endpointToAction / endpointToReadAction 现从该模块 import(见文件顶部)。
|
|
5352
5263
|
function getDeclaredActions(apiKey) {
|
|
5353
5264
|
const row = db.prepare(`SELECT declared_scope FROM agent_declarations WHERE api_key = ? AND revoked_at IS NULL`).get(apiKey);
|
|
5354
5265
|
if (!row)
|
|
@@ -7605,7 +7516,7 @@ registerOrdersReadRoutes(app, { db, auth, getOrderStatus, getOrderChain, verifyO
|
|
|
7605
7516
|
// 注意:settleOrder 是函数声明(hoisted)但绑了 db 闭包,无需注入 db
|
|
7606
7517
|
registerOrdersActionRoutes(app, {
|
|
7607
7518
|
db, auth, isTrustedRole, generateId, transition, notifyTransition,
|
|
7608
|
-
settleOrder, detectFraud, createDispute, checkTimeouts, recordViolationReputation,
|
|
7519
|
+
settleOrder, settleFault, detectFraud, createDispute, checkTimeouts, recordViolationReputation,
|
|
7609
7520
|
broadcastSystemEvent,
|
|
7610
7521
|
});
|
|
7611
7522
|
// #1013 Phase 85: POST /api/orders 巨型事务已迁出
|
|
@@ -10287,8 +10198,8 @@ db.exec(`
|
|
|
10287
10198
|
const existing = db.prepare("SELECT version FROM rewards_consent_texts WHERE version = '1.0'").get();
|
|
10288
10199
|
if (existing)
|
|
10289
10200
|
return;
|
|
10290
|
-
const textZh = 'WebAZ 共建身份(rewards opt-in)v1.0 — 由 RFC-002 §3.3 / §3.10 定义。本同意涉及经济关系登记 + Passkey 真人签名 + 三级佣金 +
|
|
10291
|
-
const textEn = 'WebAZ Builder Identity (rewards opt-in) v1.0 — defined by RFC-002 §3.3 / §3.10. This consent records an economic relationship with Passkey-signed proof of personhood + participation in 3-tier commission +
|
|
10201
|
+
const textZh = 'WebAZ 共建身份(rewards opt-in)v1.0 — 由 RFC-002 §3.3 / §3.10 定义。本同意涉及经济关系登记 + Passkey 真人签名 + 三级佣金 + 积分配对参与。详见 RFC-002 全文。本流程与购物无关,可随时退出,不影响订单。';
|
|
10202
|
+
const textEn = 'WebAZ Builder Identity (rewards opt-in) v1.0 — defined by RFC-002 §3.3 / §3.10. This consent records an economic relationship with Passkey-signed proof of personhood + participation in 3-tier commission + points-matching. See full RFC-002. This flow is not part of shopping; you may leave anytime without affecting orders.';
|
|
10292
10203
|
const hash = createHash('sha256').update(textZh + '\n---\n' + textEn).digest('hex');
|
|
10293
10204
|
db.prepare(`INSERT INTO rewards_consent_texts (version, hash, change_class, effective_at, text_zh, text_en, changelog)
|
|
10294
10205
|
VALUES (?, ?, 'major', ?, ?, ?, ?)`)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-011 §⑤ 可验证索引 —— 一份"什么可验 + 怎么验"的总表(护照/锚/AP2/订单链散在四处,这里统一)。
|
|
3
|
+
* 诚实分级(不可过度声明):
|
|
4
|
+
* - 护照 / 外部锚:公开可验(任何第三方离线 ecrecover / 验签),强。
|
|
5
|
+
* - AP2 Mandate:签名输出,可验。
|
|
6
|
+
* - 订单事件链:HMAC 是 actor 私钥 → 第三方【无法】验签;可验的是【哈希链连续性】(防篡改),且 party-gated。
|
|
7
|
+
* 只【链接 + 说明】how-to,不嵌密钥(密钥 live 发布在 did.json / protocol-status issuers),doc=code 不漂移。
|
|
8
|
+
*/
|
|
9
|
+
import { SOFTWARE_VERSION, CONTRACT_VERSION } from '../version.js';
|
|
10
|
+
const BASE = 'https://webaz.xyz';
|
|
11
|
+
export function buildVerifiabilityIndex() {
|
|
12
|
+
return {
|
|
13
|
+
contract_version: CONTRACT_VERSION,
|
|
14
|
+
software_version: SOFTWARE_VERSION,
|
|
15
|
+
note: 'RFC-011 §⑤. Each artifact lists what it proves, the scheme, how to verify, and its verifiability LEVEL — do not over-trust beyond the stated level. Issuer keys are published live (not embedded here): /.well-known/did.json + /.well-known/webaz-protocol.json#issuers.',
|
|
16
|
+
levels: {
|
|
17
|
+
public_signature: 'any third party verifies offline (ecrecover / sig-check) without calling WebAZ',
|
|
18
|
+
public_endpoint: 'verifiable via a public WebAZ endpoint (no auth)',
|
|
19
|
+
integrity_chain: 'tamper-evidence via a hash-chain (verify continuity); NOT a third-party-verifiable signature',
|
|
20
|
+
party_gated: 'full data only to order parties; others get integrity, not contents',
|
|
21
|
+
},
|
|
22
|
+
artifacts: [
|
|
23
|
+
{
|
|
24
|
+
artifact: 'agent_passport',
|
|
25
|
+
proves: 'an agent\'s custodian fingerprint + risk/engagement/behavior, signed by the WebAZ issuer key',
|
|
26
|
+
scheme: 'eip191 (EIP-191 personal_sign)',
|
|
27
|
+
level: 'public_signature',
|
|
28
|
+
offline: true,
|
|
29
|
+
how_to_verify: 'GET /api/me/agents/:apiKeyPrefix/passport → ecrecover(passport.canonical, passport.signature) == issuer address from /.well-known/did.json (CAIP-10) / /.well-known/webaz-protocol.json#issuers; check active_since/revoked_at window.',
|
|
30
|
+
endpoint: `${BASE}/api/me/agents/:apiKeyPrefix/passport`,
|
|
31
|
+
keys: `${BASE}/.well-known/did.json`,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
artifact: 'external_anchor',
|
|
35
|
+
proves: 'a real-world item\'s ownership/authenticity anchor + independent verifier attestations',
|
|
36
|
+
scheme: 'signature (server-verifiable)',
|
|
37
|
+
level: 'public_endpoint',
|
|
38
|
+
offline: false,
|
|
39
|
+
how_to_verify: `GET ${BASE}/api/external-anchors/:id/verify-sig (public); cross-check verifier attestations via /api/external-anchors/:id.`,
|
|
40
|
+
endpoint: `${BASE}/api/external-anchors/:id/verify-sig`,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
artifact: 'ap2_mandate',
|
|
44
|
+
proves: 'a buyer\'s signed Intent/Cart/Payment Mandate (AP2) emitted alongside the webaz price/order format',
|
|
45
|
+
scheme: 'AP2 signed mandate',
|
|
46
|
+
level: 'public_signature',
|
|
47
|
+
offline: true,
|
|
48
|
+
how_to_verify: 'verify the AP2 mandate signature per the AP2 spec; emitted by webaz_verify_price + webaz_place_order (dual-output).',
|
|
49
|
+
endpoint: 'returned inline by verify_price / place_order',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
artifact: 'order_event_chain',
|
|
53
|
+
proves: 'the order/dispute transition history is append-only + tamper-evident (each event hash chains to the previous)',
|
|
54
|
+
scheme: 'sha256 hash-chain (event_hash / prev_event_hash). NOTE: the per-event `signature` is an HMAC with the actor\'s api_key — NOT third-party verifiable; the verifiable property is the HASH-CHAIN continuity.',
|
|
55
|
+
level: 'integrity_chain',
|
|
56
|
+
offline: true,
|
|
57
|
+
party_gated: true,
|
|
58
|
+
how_to_verify: `For an order you are party to: GET ${BASE}/api/orders/:id/chain (returns chain + verification). Or stream events via ${BASE}/api/agent/events (§⑥): check each event\'s prev_event_hash == the previous event\'s event_hash. Continuity proves no insert/delete/reorder.`,
|
|
59
|
+
endpoint: `${BASE}/api/orders/:id/chain`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for WebAZ version axes — RFC-011 §④ (version hygiene).
|
|
3
|
+
*
|
|
4
|
+
* TWO DISTINCT AXES. Do not conflate them — conflating is exactly the dirt this file kills
|
|
5
|
+
* (the old hardcoded MCP `SERVER_VERSION='0.1.8'` + Server handshake `version:'0.1.0'` drifted
|
|
6
|
+
* away from the real package version 0.1.19; this makes that structurally impossible).
|
|
7
|
+
*
|
|
8
|
+
* 1. SOFTWARE_VERSION — npm / release semver of THIS codebase (MCP client+server + PWA).
|
|
9
|
+
* Read from package.json at runtime so it can NEVER drift. Bumps on every release.
|
|
10
|
+
* Resolves from both dev (tsx src/version.ts → ../package.json) and prod/published
|
|
11
|
+
* (node dist/version.js → ../package.json), since package.json sits at the package root
|
|
12
|
+
* and is always included in the npm tarball.
|
|
13
|
+
*
|
|
14
|
+
* 2. CONTRACT_VERSION — the agent-native INTEGRATION CONTRACT version (manifest `schema_version`).
|
|
15
|
+
* A deliberate integer that integrators' agents key off. Bump ONLY on a *breaking* change to
|
|
16
|
+
* the data contract they read (entity shape / boundary / verifiable-field semantics).
|
|
17
|
+
* INDEPENDENT of software releases — a patch/feature release does NOT bump it; a breaking
|
|
18
|
+
* contract change DOES, even within the same software version. Governs RFC-011's contract.
|
|
19
|
+
*
|
|
20
|
+
* Both are surfaced to integrators in /.well-known/webaz-protocol.json so an agent can read
|
|
21
|
+
* "contract vN running software x.y.z" and decide compatibility.
|
|
22
|
+
*/
|
|
23
|
+
import { createRequire } from 'node:module';
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
const pkg = require('../package.json');
|
|
26
|
+
/** npm/release semver — single source = package.json. Never hardcode a copy of this. */
|
|
27
|
+
export const SOFTWARE_VERSION = pkg.version;
|
|
28
|
+
/** Integration-contract version. Bump on ANY integrator-observable contract-surface change
|
|
29
|
+
* (capability matrix §② / entity dictionary §①); the CONTRACT_CHANGES `kind` classifies whether
|
|
30
|
+
* it is breaking. Additive changes (kind:'added') are safe for agents to ignore. Guarded by
|
|
31
|
+
* tests/test-contract-fingerprint.ts + docs/CONTRACT-LOCK.json. */
|
|
32
|
+
export const CONTRACT_VERSION = 2;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seasonkoh/webaz",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "[PRE-LAUNCH] Agent-native decentralized commerce protocol. Humans and AI agents trade on the same protocol via MCP tools. ⚠️ Repository currently private until W8 public launch — GitHub links may return 404. See https://webaz.xyz for status.",
|
|
5
5
|
"main": "dist/mcp.js",
|
|
6
6
|
"bin": {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"enforcement": "tsx src/cron-enforcement.ts",
|
|
21
21
|
"pwa": "tsx src/pwa/server.ts",
|
|
22
22
|
"schema:verify": "tsx scripts/schema-verify.ts",
|
|
23
|
+
"contract:verify": "tsx tests/test-contract-fingerprint.ts",
|
|
23
24
|
"license:check": "tsx scripts/license-invariant-check.ts",
|
|
24
25
|
"meta-rules:check": "tsx scripts/meta-rules-invariant-check.ts",
|
|
25
26
|
"params:check": "tsx scripts/meta-rule-locked-params-check.ts"
|