@agentsfleet/orly 0.9.4 → 0.10.1
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/AGENTS.md +1 -1
- package/audits/design-tokens.sh +57 -5
- package/core/operating-model.md +1 -1
- package/dispatch/write_changelog.md +4 -2
- package/dispatch/write_pr_description.md +36 -0
- package/docs/CHANGELOG_VOICE.md +1 -1
- package/package.json +1 -1
- package/registry.json +0 -4
- package/audits/cross-tier-rates.sh +0 -105
package/AGENTS.md
CHANGED
|
@@ -144,7 +144,7 @@ Guards fire pre-hoc regardless of lifecycle stage. Override: `<GATE>: SKIPPED pe
|
|
|
144
144
|
| write auth-flow / token-minting files | `write_auth` | `dispatch/write_auth.md` — auth invariants; reads the product repo's `docs/AUTH.md` before · 🟣 delegated (product repo). |
|
|
145
145
|
| write published docs / OpenAPI prose | `write_documentation` | `dispatch/write_documentation.md` → `docs/DOCUMENTATION_RULES.md` before narrower guides; page, fragment, API, changelog scopes differ · 🟣 delegated to repository pre-commit checks. |
|
|
146
146
|
| write a changelog entry | `write_changelog` | `dispatch/write_changelog.md` — changelog voice (one headline, no marketing words, `**Bold lead-noun**` bullets, history append-only); reads `docs/CHANGELOG_VOICE.md` · 🤔 judgment-only. |
|
|
147
|
-
| write/update a PR or MR body or its session notes | `write_pr_description` | `dispatch/write_pr_description.md` — append numbered `Session notes`, `Review`, and `Make`; measured fenced diagrams; review dispositions; commands with real output. |
|
|
147
|
+
| write/update a PR or MR body or its session notes | `write_pr_description` | `dispatch/write_pr_description.md` — append numbered `Session notes`, `Review`, and `Make`; measured fenced diagrams; visual evidence from the lane's own artifacts; review dispositions; commands with real output. |
|
|
148
148
|
| claim "tests pass / ready / shipping" | `verify` | `dispatch/verify.md` — verification tiers (`make` canonical; package-scoped runners are **not** verification), done-message glyph format · 🤔 judgment-only, `VERIFY GATE: <target> skipped per environment constraint (reason: ...)` only when genuinely unrunnable. |
|
|
149
149
|
| name a stream/channel/Redis namespace/queue/RPC/Postgres schema, or describe a flow | `name_architecture` | `dispatch/name_architecture.md` — architecture-consult discipline; grep relevant `docs/architecture/` (chat brainstorming counts) · **no override** — doc wins until reconciled. |
|
|
150
150
|
| run a lifecycle stage (open→close a stream, worktree setup, milestone bootstrap) | `lifecycle` | `dispatch/lifecycle.md` — stage runbooks: CHORE(open/close) checklists, PLAN expansions, spec discipline, deferral format, pre-PR gates, LAND · 🤔 judgment-only. |
|
package/audits/design-tokens.sh
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# design-tokens.sh — enforce design-system token discipline
|
|
3
|
-
#
|
|
2
|
+
# design-tokens.sh — enforce design-system token discipline and flat fills
|
|
3
|
+
# across the app, website, and shared design system.
|
|
4
4
|
#
|
|
5
5
|
# Dispatch façade: dispatch/write_ts_adhere_bun.md (Design Tokens / DESIGN TOKEN GATE)
|
|
6
6
|
# Fires in: CONFORM (via `make harness-verify` in `agentsfleet`).
|
|
@@ -62,6 +62,23 @@ PATTERNS=(
|
|
|
62
62
|
'(text|bg|border)-(red|blue|green|yellow|purple|indigo|violet|pink|orange|gray|slate|zinc|neutral)-[0-9]:::use semantic tokens (text-destructive, text-error, text-success, …)'
|
|
63
63
|
)
|
|
64
64
|
|
|
65
|
+
readonly GRADIENT_REGEX='(repeating-)?(linear|radial|conic)-gradient[[:space:]]*\('
|
|
66
|
+
|
|
67
|
+
# Consumers may select a font role, but only the design system defines it.
|
|
68
|
+
check_font_ownership() {
|
|
69
|
+
local f="$1"
|
|
70
|
+
case "$f" in ui/packages/design-system/*) return ;; esac
|
|
71
|
+
awk '
|
|
72
|
+
{
|
|
73
|
+
source = $0
|
|
74
|
+
gsub(/font-family[[:space:]]*:[[:space:]]*var\(--ff-(sans|mono|display)\)/, "")
|
|
75
|
+
invalid = /font-family[[:space:]]*:|fontFamily[[:space:]]*:[[:space:]]*["\047]|--(ff|font)-(sans|mono|display)[[:space:]]*:|font-\[/
|
|
76
|
+
if (FILENAME ~ /^ui\/packages\/app\// && /font-display|DisplayXL|DisplayLG/) invalid = 1
|
|
77
|
+
if (invalid) printf "%s:%d:%s\n", FILENAME, FNR, source
|
|
78
|
+
}
|
|
79
|
+
' "$f"
|
|
80
|
+
}
|
|
81
|
+
|
|
65
82
|
# ── File scope ───────────────────────────────────────────────────────────
|
|
66
83
|
in_scope() {
|
|
67
84
|
local f="$1"
|
|
@@ -70,8 +87,17 @@ in_scope() {
|
|
|
70
87
|
*tests/e2e/*) return 1 ;;
|
|
71
88
|
ui/packages/app/*.tsx|ui/packages/app/*.jsx) return 0 ;;
|
|
72
89
|
ui/packages/website/*.tsx|ui/packages/website/*.jsx) return 0 ;;
|
|
73
|
-
|
|
74
|
-
|
|
90
|
+
*) return 1 ;;
|
|
91
|
+
esac
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
in_gradient_scope() {
|
|
95
|
+
local f="$1"
|
|
96
|
+
case "$f" in
|
|
97
|
+
*.test.*|*.spec.*|*/tests/*|*/coverage/*|*/dist/*|*/.next/*|*/node_modules/*) return 1 ;;
|
|
98
|
+
ui/packages/app/*.css|ui/packages/app/*.js|ui/packages/app/*.jsx|ui/packages/app/*.mjs|ui/packages/app/*.ts|ui/packages/app/*.tsx) return 0 ;;
|
|
99
|
+
ui/packages/website/*.css|ui/packages/website/*.js|ui/packages/website/*.jsx|ui/packages/website/*.mjs|ui/packages/website/*.ts|ui/packages/website/*.tsx) return 0 ;;
|
|
100
|
+
ui/packages/design-system/*.css|ui/packages/design-system/*.js|ui/packages/design-system/*.jsx|ui/packages/design-system/*.mjs|ui/packages/design-system/*.ts|ui/packages/design-system/*.tsx) return 0 ;;
|
|
75
101
|
*) return 1 ;;
|
|
76
102
|
esac
|
|
77
103
|
}
|
|
@@ -79,12 +105,14 @@ in_scope() {
|
|
|
79
105
|
case "$MODE" in
|
|
80
106
|
--staged|staged)
|
|
81
107
|
FILES=$(git diff --cached --name-only --diff-filter=ACMRT 2>/dev/null || true)
|
|
108
|
+
GRADIENT_CANDIDATES="$FILES"
|
|
82
109
|
;;
|
|
83
110
|
--all|all)
|
|
84
111
|
# `git ls-files` reports the index, which includes staged content —
|
|
85
112
|
# so pre-commit-style invocations see staged-but-not-committed files
|
|
86
113
|
# without needing a `--staged` flag.
|
|
87
114
|
FILES=$(git ls-files -- 'ui/packages/app/*.tsx' 'ui/packages/app/*.jsx' 'ui/packages/website/*.tsx' 'ui/packages/website/*.jsx' 2>/dev/null || true)
|
|
115
|
+
GRADIENT_CANDIDATES=$(git ls-files -- ui/packages/app ui/packages/website ui/packages/design-system 2>/dev/null || true)
|
|
88
116
|
;;
|
|
89
117
|
*)
|
|
90
118
|
echo "usage: $0 [--all|--staged]" >&2
|
|
@@ -127,10 +155,34 @@ if [ "${#SCOPED_FILES[@]}" -gt 0 ]; then
|
|
|
127
155
|
done
|
|
128
156
|
fi
|
|
129
157
|
|
|
158
|
+
GRADIENT_FILES=()
|
|
159
|
+
while IFS= read -r f; do
|
|
160
|
+
[ -z "$f" ] && continue
|
|
161
|
+
[ ! -f "$f" ] && continue
|
|
162
|
+
in_gradient_scope "$f" || continue
|
|
163
|
+
GRADIENT_FILES+=("$f")
|
|
164
|
+
while IFS= read -r match; do
|
|
165
|
+
[ -z "$match" ] && continue
|
|
166
|
+
printf '%s\n -> define fonts in design-system tokens.css; use sans for app UI and mono for technical values\n' "$match"
|
|
167
|
+
SEEN_FILES_LIST="${SEEN_FILES_LIST}${f}"$'\n'
|
|
168
|
+
FAIL=1
|
|
169
|
+
done < <(check_font_ownership "$f")
|
|
170
|
+
done <<< "$GRADIENT_CANDIDATES"
|
|
171
|
+
|
|
172
|
+
if [ "${#GRADIENT_FILES[@]}" -gt 0 ]; then
|
|
173
|
+
while IFS= read -r match; do
|
|
174
|
+
[ -z "$match" ] && continue
|
|
175
|
+
f="${match%%:*}"
|
|
176
|
+
printf '%s\n -> use a solid design-system color token; gradients are forbidden\n' "$match"
|
|
177
|
+
SEEN_FILES_LIST="${SEEN_FILES_LIST}${f}"$'\n'
|
|
178
|
+
FAIL=1
|
|
179
|
+
done < <(grep -nHE "$GRADIENT_REGEX" "${GRADIENT_FILES[@]}" 2>/dev/null || true)
|
|
180
|
+
fi
|
|
181
|
+
|
|
130
182
|
FILES_WITH_VIOLATIONS=$(printf '%s' "$SEEN_FILES_LIST" | sort -u | grep -c . || true)
|
|
131
183
|
|
|
132
184
|
if [ "$FAIL" = "0" ]; then
|
|
133
|
-
echo "OK: design-token discipline —
|
|
185
|
+
echo "OK: design-token discipline — named utilities and flat fills verified (mode=$MODE)"
|
|
134
186
|
exit 0
|
|
135
187
|
fi
|
|
136
188
|
|
package/core/operating-model.md
CHANGED
|
@@ -148,7 +148,7 @@ Guards fire pre-hoc regardless of lifecycle stage. Override: `<GATE>: SKIPPED pe
|
|
|
148
148
|
| write auth-flow / token-minting files | `write_auth` | `dispatch/write_auth.md` — auth invariants; reads the product repo's `docs/AUTH.md` before · 🟣 delegated (product repo). | <!-- oracle-packs:domain.auth -->
|
|
149
149
|
| write published docs / OpenAPI prose | `write_documentation` | `dispatch/write_documentation.md` → `docs/DOCUMENTATION_RULES.md` before narrower guides; page, fragment, API, changelog scopes differ · 🟣 delegated to repository pre-commit checks. | <!-- oracle-packs:domain.documentation -->
|
|
150
150
|
| write a changelog entry | `write_changelog` | `dispatch/write_changelog.md` — changelog voice (one headline, no marketing words, `**Bold lead-noun**` bullets, history append-only); reads `docs/CHANGELOG_VOICE.md` · 🤔 judgment-only. | <!-- oracle-packs:domain.changelog -->
|
|
151
|
-
| write/update a PR or MR body or its session notes | `write_pr_description` | `dispatch/write_pr_description.md` — append numbered `Session notes`, `Review`, and `Make`; measured fenced diagrams; review dispositions; commands with real output. | <!-- oracle-packs:universal.authoring -->
|
|
151
|
+
| write/update a PR or MR body or its session notes | `write_pr_description` | `dispatch/write_pr_description.md` — append numbered `Session notes`, `Review`, and `Make`; measured fenced diagrams; visual evidence from the lane's own artifacts; review dispositions; commands with real output. | <!-- oracle-packs:universal.authoring -->
|
|
152
152
|
| claim "tests pass / ready / shipping" | `verify` | `dispatch/verify.md` — verification tiers (`make` canonical; package-scoped runners are **not** verification), done-message glyph format · 🤔 judgment-only, `VERIFY GATE: <target> skipped per environment constraint (reason: ...)` only when genuinely unrunnable. | <!-- oracle-packs:product.agentsfleet -->
|
|
153
153
|
| name a stream/channel/Redis namespace/queue/RPC/Postgres schema, or describe a flow | `name_architecture` | `dispatch/name_architecture.md` — architecture-consult discipline; grep relevant `docs/architecture/` (chat brainstorming counts) · **no override** — doc wins until reconciled. | <!-- oracle-packs:universal.authoring -->
|
|
154
154
|
| run a lifecycle stage (open→close a stream, worktree setup, milestone bootstrap) | `lifecycle` | `dispatch/lifecycle.md` — stage runbooks: CHORE(open/close) checklists, PLAN expansions, spec discipline, deferral format, pre-PR gates, LAND · 🤔 judgment-only. |
|
|
@@ -40,8 +40,10 @@ a gate skip.
|
|
|
40
40
|
names, money amounts stay verbatim.
|
|
41
41
|
- **Internal cleanup** gets aggressive trimming, not a paragraph.
|
|
42
42
|
- **History is archived, not rewritten** — past entries are an immutable record.
|
|
43
|
-
- **Rate constants**
|
|
44
|
-
|
|
43
|
+
- **Rate constants** are pinned by `cross_runtime_rates.rs`, which reads the
|
|
44
|
+
app and Command-Line Interface (CLI) mirrors against the Rust constant. A
|
|
45
|
+
changelog money or rate claim must match those, and `rates.mdx` in the docs
|
|
46
|
+
repository, which no test can reach.
|
|
45
47
|
|
|
46
48
|
## Required output (self-audit line before committing the changelog)
|
|
47
49
|
|
|
@@ -84,6 +84,37 @@ their numbers:
|
|
|
84
84
|
0.003-0.005ms 0.1ms 1.0ms 12-21ms
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
## Visual evidence
|
|
88
|
+
|
|
89
|
+
A change to a surface a person looks at, or a failure a picture explains faster
|
|
90
|
+
than a paragraph, carries the picture. A reviewer who can see the wall, the
|
|
91
|
+
dialog or the red run decides in seconds what a description makes them
|
|
92
|
+
reconstruct.
|
|
93
|
+
|
|
94
|
+
**Take it from what already ran, not from a staged pose.** A lane that failed
|
|
95
|
+
has already produced the image: `gh run download <id> -n <artifact>` yields
|
|
96
|
+
Playwright's `test-failed-*.png`, its `trace.zip` and its `error-context.md`.
|
|
97
|
+
Those are measured evidence of the state under review. A browser driven by hand
|
|
98
|
+
is the fallback, for a surface no lane photographs.
|
|
99
|
+
|
|
100
|
+
**Screenshot the claim, not the neighbourhood.** One image per assertion, and
|
|
101
|
+
the assertion named in the caption — "one tile, not two" beats "the fleets
|
|
102
|
+
page". Never crop a failure out of a frame that contained it.
|
|
103
|
+
|
|
104
|
+
**Attaching is the author's step, and say so rather than pretending.** No forge
|
|
105
|
+
accepts an image upload to a pull-request body over its command-line interface;
|
|
106
|
+
`gh` and `glab` both have no such call. So the agent hands the file to the
|
|
107
|
+
person and the person drags it in. What the agent MUST do in the body is make
|
|
108
|
+
the evidence retrievable without the image: name the run id, the artifact and
|
|
109
|
+
the path inside it, and quote the decisive line. A body that says
|
|
110
|
+
`error-context.md:27 records unexpected value "hidden"` survives a screenshot
|
|
111
|
+
nobody attached; a body that says "see screenshot" does not.
|
|
112
|
+
|
|
113
|
+
**A before/after belongs in a fence, not in two images**, when the difference is
|
|
114
|
+
countable — the diagram rules above already cover it, and a diagram diffs
|
|
115
|
+
better than a pair of pictures. Use images for what only rendering shows:
|
|
116
|
+
alignment, spacing, contrast, what a person actually sees.
|
|
117
|
+
|
|
87
118
|
## Review
|
|
88
119
|
|
|
89
120
|
Lead with the review result. Record every finding with P0, P1, or P2 severity,
|
|
@@ -142,6 +173,11 @@ a green pipeline.
|
|
|
142
173
|
<Useful measured diagram, at most 78 columns.>
|
|
143
174
|
```
|
|
144
175
|
|
|
176
|
+
<Visual evidence, when a surface changed or a picture explains a failure:
|
|
177
|
+
each image named with the assertion it carries and with the run, artifact and
|
|
178
|
+
path it came from, plus the decisive line quoted so the claim survives an
|
|
179
|
+
image nobody attached.>
|
|
180
|
+
|
|
145
181
|
## Review
|
|
146
182
|
|
|
147
183
|
<P0/P1/P2 entries with dispositions, No findings., or not-run reason.>
|
package/docs/CHANGELOG_VOICE.md
CHANGED
|
@@ -14,5 +14,5 @@ Editing `~/Projects/docs/changelog.mdx` or any other Mintlify `<Update>` block.
|
|
|
14
14
|
- **Internal cleanup / refactor entries get the most aggressive trimming.** One lead paragraph + one bullet list. Skip "Test coverage" sections unless the test count is the headline. Indy's exact direction: *"Keep internal code cleanup, refactor to a minimal."*
|
|
15
15
|
- **Never drop load-bearing facts.** Error codes (`UZ-AUTH-003`), endpoint paths + method + body shape + status code, env var names + defaults, schema column / table names, CLI subcommand + flag names, migration steps, money amounts. Tighten prose, not meaning.
|
|
16
16
|
- **Historical entries are archives.** Brevity-pass them; never rewrite the past. A typo correction (e.g. `$0.001` → `$0.01` when it was never true) is allowed and must be called out in the commit message.
|
|
17
|
-
- **Rate constants
|
|
17
|
+
- **Rate constants stay pinned across the runtime surfaces, and a test says so.** `rustd/crates/afd_billing/tests/cross_runtime_rates.rs` reads `ui/packages/app/lib/types.ts` and `cli/src/constants/billing.ts` and fails when either drifts from `rustd/crates/afd_billing/src/nanos.rs` — a test beside the constant it defends, not a gate nothing invokes. Public docs are the one surface it cannot reach: when a rate changes, update `~/Projects/docs/snippets/rates.mdx` in a paired Pull Request (PR). In `*.mdx`, import its named values rather than hand-typing money amounts.
|
|
18
18
|
- **The Mintlify reference Indy pasted (May 1 / May 8 entries) is canonical voice.** Mirror its rhythm, not its product nouns.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentsfleet/orly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Repository-scoped engineering harness: renders agent rules, materialises the gates that enforce them, and proves the PR boundary \u2014 for any coding agent.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/registry.json
CHANGED
|
@@ -296,10 +296,6 @@
|
|
|
296
296
|
"product.agentsfleet": {
|
|
297
297
|
"extensions": [],
|
|
298
298
|
"managed_files": [
|
|
299
|
-
{
|
|
300
|
-
"source": "audits/cross-tier-rates.sh",
|
|
301
|
-
"target": "audits/cross-tier-rates.sh"
|
|
302
|
-
},
|
|
303
299
|
{
|
|
304
300
|
"source": "audits/design-tokens.sh",
|
|
305
301
|
"target": "audits/design-tokens.sh"
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# cross-tier-rates.sh — pin numeric parity of the rate constants
|
|
3
|
-
# across the daemon + three TypeScript surfaces.
|
|
4
|
-
#
|
|
5
|
-
# RULE UFS extension. The shipped billing surface depends on these constants
|
|
6
|
-
# having identical numeric values everywhere they appear:
|
|
7
|
-
#
|
|
8
|
-
# RUN_NANOS_PER_SEC — per-second run rate (both postures) in nanos
|
|
9
|
-
#
|
|
10
|
-
# Two free-trial constants were pinned here and are both gone. FREE_TRIAL_END_MS
|
|
11
|
-
# went when the boundary moved onto the tenant row; FREE_TRIAL_STAGE_NANOS went
|
|
12
|
-
# when the trial mechanism was removed outright, because a rate that could
|
|
13
|
-
# silently price a metered slice to zero was worth deleting rather than
|
|
14
|
-
# guarding. The free allowance is wallet credit now — a balance, not a rate —
|
|
15
|
-
# so there is no cross-tier number to pin for it.
|
|
16
|
-
#
|
|
17
|
-
# Files (one definition site per constant per file):
|
|
18
|
-
#
|
|
19
|
-
# rustd/crates/afd_billing/src/nanos.rs — server enforces the charge
|
|
20
|
-
# ui/packages/website/src/lib/rates.ts — pricing page display
|
|
21
|
-
# ui/packages/app/lib/types.ts — dashboard display
|
|
22
|
-
# cli/src/constants/billing.ts — `agentsfleet doctor --json` billing block
|
|
23
|
-
#
|
|
24
|
-
# A drift between any two = a billing-display lie or a server-vs-CLI disagreement.
|
|
25
|
-
# The daemon is the source of truth (server enforces); the three TS surfaces echo it.
|
|
26
|
-
#
|
|
27
|
-
# Fires in: make harness-verify, make harness-verify-all.
|
|
28
|
-
# Exits 0 clean, 1 on any drift.
|
|
29
|
-
|
|
30
|
-
set -euo pipefail
|
|
31
|
-
|
|
32
|
-
ROOT="$(git rev-parse --show-toplevel)"
|
|
33
|
-
cd "$ROOT"
|
|
34
|
-
|
|
35
|
-
readonly NAMES=(
|
|
36
|
-
RUN_NANOS_PER_SEC
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
readonly FILES=(
|
|
40
|
-
rustd/crates/afd_billing/src/nanos.rs
|
|
41
|
-
ui/packages/website/src/lib/rates.ts
|
|
42
|
-
ui/packages/app/lib/types.ts
|
|
43
|
-
cli/src/constants/billing.ts
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
# Extract the numeric value bound to `name` in `file`. Matches definition
|
|
47
|
-
# sites only — `^(pub |export )?const NAME` — not usages elsewhere in the
|
|
48
|
-
# file. Normalises: strips underscores (Zig `1_000_000`, TS `1_000_000`),
|
|
49
|
-
# strips the bigint `n` suffix (TS `1_000_000n`), trims whitespace.
|
|
50
|
-
extract_value() {
|
|
51
|
-
local file="$1" name="$2"
|
|
52
|
-
grep -E "^[[:space:]]*(pub |export )?const ${name}\\b" "$file" 2>/dev/null \
|
|
53
|
-
| head -1 \
|
|
54
|
-
| sed -E "s|.*=[[:space:]]*||; s|[;,].*||; s|//.*||; s|[[:space:]_n]||g"
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
FAIL=0
|
|
58
|
-
violations=()
|
|
59
|
-
|
|
60
|
-
printf "audit-cross-tier-rates: pinning %d constants across %d files\n" \
|
|
61
|
-
"${#NAMES[@]}" "${#FILES[@]}"
|
|
62
|
-
|
|
63
|
-
for name in "${NAMES[@]}"; do
|
|
64
|
-
expected=""
|
|
65
|
-
expected_file=""
|
|
66
|
-
for file in "${FILES[@]}"; do
|
|
67
|
-
if [[ ! -f "$file" ]]; then
|
|
68
|
-
violations+=("MISSING_FILE: $file")
|
|
69
|
-
FAIL=1
|
|
70
|
-
continue
|
|
71
|
-
fi
|
|
72
|
-
val="$(extract_value "$file" "$name")"
|
|
73
|
-
if [[ -z "$val" ]]; then
|
|
74
|
-
violations+=("MISSING_CONST: $name not defined in $file")
|
|
75
|
-
FAIL=1
|
|
76
|
-
continue
|
|
77
|
-
fi
|
|
78
|
-
if [[ -z "$expected" ]]; then
|
|
79
|
-
expected="$val"
|
|
80
|
-
expected_file="$file"
|
|
81
|
-
continue
|
|
82
|
-
fi
|
|
83
|
-
if [[ "$val" != "$expected" ]]; then
|
|
84
|
-
violations+=("DRIFT: $name = $val in $file vs $expected in $expected_file")
|
|
85
|
-
FAIL=1
|
|
86
|
-
fi
|
|
87
|
-
done
|
|
88
|
-
if [[ -n "$expected" ]]; then
|
|
89
|
-
printf " OK %-26s = %s\n" "$name" "$expected"
|
|
90
|
-
fi
|
|
91
|
-
done
|
|
92
|
-
|
|
93
|
-
if [[ $FAIL -ne 0 ]]; then
|
|
94
|
-
printf "\nFAIL: cross-tier rate drift detected:\n" >&2
|
|
95
|
-
for v in "${violations[@]}"; do
|
|
96
|
-
printf " %s\n" "$v" >&2
|
|
97
|
-
done
|
|
98
|
-
printf "\nFix: align all four files on the canonical Zig value\n" >&2
|
|
99
|
-
printf " (rustd/crates/afd_billing/src/nanos.rs is the server-side enforcer).\n" >&2
|
|
100
|
-
exit 1
|
|
101
|
-
fi
|
|
102
|
-
|
|
103
|
-
printf "OK: all %d rate constants pin across %d files\n" \
|
|
104
|
-
"${#NAMES[@]}" "${#FILES[@]}"
|
|
105
|
-
exit 0
|