feat: add source-owned combat mechanic programs
This commit is contained in:
+216
-49
@@ -713,7 +713,7 @@ augmentation cell communicates that this talent advances to Tier II.
|
||||
The exotic talent is owned by exactly one exotic weapon and is authored inline
|
||||
inside that weapon editor, never selected from a shared global pool. Its
|
||||
engineered sub-panel includes the talent name, shared description template,
|
||||
Tier I/II previews, reusable triggers, and paired effect values. The Talent
|
||||
Tier I/II previews, and the shared source-owned mechanic program editor. The Talent
|
||||
Registry may display an owned exotic talent for discovery, but routes editing
|
||||
back to its weapon rather than opening the shared-talent editor.
|
||||
|
||||
@@ -816,9 +816,9 @@ the base until five upgrades show exactly twice the base effect.
|
||||
|
||||
Diamonds are both a progression preview and an explicit numeric state; expose
|
||||
their upgrade number and `aria-pressed` state rather than relying on fill color.
|
||||
Protocol talents own their effects but reuse the global stat and trigger
|
||||
registries. Shared secondary values do not scale with the individual protocol’s
|
||||
level. Store only the unique primary and talent base values, and derive their
|
||||
Protocol Talents own their mechanic programs and reuse the global Attribute
|
||||
registry. Shared secondary values do not scale with the individual protocol’s
|
||||
level. Store only the unique primary and Talent base values, and derive their
|
||||
progression consistently in calculation and display code.
|
||||
|
||||
### ISAC editor lifecycle
|
||||
@@ -835,16 +835,16 @@ text is operationally useful. Use compact wrapping description cells rather
|
||||
than replacing meaningful data with a generic “configured” label; retain an
|
||||
explicit textual missing state when a tier has no rendered description.
|
||||
|
||||
Talent mechanics are structured metadata, not free-form prose. Present optional
|
||||
cooldown, duration, and maximum-stack inputs together in a compact three-column
|
||||
mechanics strip that collapses to one column on narrow screens. Description
|
||||
templates use numbered expressions (`{1}`, `{2}`) for tiered attribute effects
|
||||
and named expressions (`{duration}`, `{max_stacks}`) for shared mechanics.
|
||||
Named expressions are valid only when their corresponding value is defined.
|
||||
Cooldown is never embedded in the description: render it consistently as
|
||||
`Talent Cooldown: [value] seconds` beneath the talent identity or description.
|
||||
Do not imply an absent mechanic with a zero value; show no cooldown line and
|
||||
leave optional editor fields explicitly marked as not defined.
|
||||
Talent mechanics are structured metadata, not free-form prose. Author
|
||||
cooldowns on event branches, durations and maximum stacks on state pools, and
|
||||
tier values on outcomes through `MechanicProgramEditor`. Description templates
|
||||
use numbered expressions (`{1}`, `{2}`) for ordered outcomes and named
|
||||
expressions (`{duration}`, `{max_stacks}`) for defined pool mechanics. Named
|
||||
expressions are valid only when their corresponding value exists. Cooldown is
|
||||
never embedded in the description: render it consistently as `Talent
|
||||
Cooldown: [value] seconds` beneath the talent identity or description. Do not
|
||||
imply an absent mechanic with a zero value; omit the cooldown line when no
|
||||
branch defines one.
|
||||
|
||||
### Registry pagination
|
||||
|
||||
@@ -916,8 +916,8 @@ bookmarkable, and expose the selected state with both orange emphasis and
|
||||
`aria-current`. Cards require pointer, hover, focus-visible, pressed, and
|
||||
textually identifiable active states. Every card explicitly says `FILTER →`
|
||||
or `SELECTED`; do not rely on KPI-card styling alone to communicate that the
|
||||
metrics are controls. Counts describe the full search scope,
|
||||
not merely the visible page. Replace aggregate facts that cannot filter the
|
||||
metrics are controls. Counts describe the full search scope and never only the
|
||||
visible page. Replace aggregate facts that cannot filter the
|
||||
affected registry with actionable subsets.
|
||||
|
||||
### Registry row interaction
|
||||
@@ -963,8 +963,8 @@ Show contributor access banners only on Data Management modules. Show the
|
||||
data-mode controls and language from User Operations, System Oversight, and
|
||||
System Configuration because their permissions govern access independently.
|
||||
Read-only mode is an inspection surface: hide add controls, row edit actions,
|
||||
mutation forms, and editors opened through URL state. Do not merely dim or
|
||||
disable them. Registry navigation, KPI filters, pagination, search, evidence,
|
||||
mutation forms, and editors opened through URL state. Dimming or disabling
|
||||
those controls is insufficient. Registry navigation, KPI filters, pagination, search, evidence,
|
||||
and other non-mutating inspection controls remain visible and interactive.
|
||||
|
||||
The ISAC command-status cluster includes system state, access state, the themed
|
||||
@@ -1293,8 +1293,8 @@ The primary `name` field in each ISAC data editor is a 46-pixel header-level
|
||||
input with larger, heavier text. It gives long registries a consistent first
|
||||
reading point while keeping secondary metadata compact.
|
||||
|
||||
`SearchableAssignment` is the standard relationship picker for long attribute,
|
||||
talent, trigger, and compatibility lists. Multiple mode manages additive sets;
|
||||
`SearchableAssignment` is the standard relationship picker for long Attribute,
|
||||
Talent, event, and compatibility lists. Multiple mode manages additive sets;
|
||||
single mode presents the same searchable selected/result treatment for one
|
||||
relationship. Prefer these modes over native selects once a source registry is
|
||||
large enough that scanning a dropdown is inefficient. The selected record,
|
||||
@@ -1397,10 +1397,11 @@ such as the single-exotic-weapon rule are explained rather than hidden.
|
||||
Numeric instance values display their authoritative minimum and maximum beside
|
||||
the field and clamp to that range on completion. Always-on item rolls, fixed
|
||||
bonuses, inherited profiles, enabled augments, and activated set bonuses feed
|
||||
the live totals immediately. Trigger-dependent talents remain explicitly
|
||||
`CONDITIONAL` until the user enables `TRIGGER ACTIVE`; only then may their
|
||||
effects enter combined totals. This textual distinction must remain clear
|
||||
without relying on color.
|
||||
the live totals immediately. Conditional mechanics state their calculation
|
||||
mode and readiness. Maximum Potential uses their best-case state; Custom
|
||||
Scenario uses the source-defined advanced assumptions saved with the loadout.
|
||||
Exclude a mechanic that lacks a required assumption and label it `REQUIRES
|
||||
ASSUMPTIONS`. This distinction must remain clear without relying on color.
|
||||
|
||||
### Pending ISAC registry records
|
||||
|
||||
@@ -1844,23 +1845,165 @@ positive whole-number quantities for Rank 2. Rank 3 uses the yellow High-end
|
||||
Omega treatment and exactly one component. Color is supporting hierarchy;
|
||||
quality names and quantities always remain visible.
|
||||
|
||||
### Conditional combat modeling
|
||||
### Source-owned mechanic program editor
|
||||
|
||||
ISAC authors define a combat effect once per Specialization and attach it to
|
||||
one or more tree-node ranks. Each rank attachment owns its hit trigger, stack
|
||||
duration, stack limit, and Attribute modifiers. Keep the lifecycle rules in a
|
||||
compact fact rail: trigger counters reset after a proc, each stack gain refreshes
|
||||
the timer, and expiry clears the complete stack. The shared definition provides
|
||||
one effect name and description to every attached rank.
|
||||
Use `MechanicProgramEditor` for every calculation-ready standard or exotic
|
||||
Talent, OS Protocol Talent, Skill Chip Talent, and Specialization tree-rank
|
||||
effect. The program stays inside its owning source editor and contribution
|
||||
payload. Do not create a standalone Trigger registry, Trigger assignment
|
||||
control, or shared Trigger lifecycle.
|
||||
|
||||
Use `--shd-model-surface` and `--shd-model-border` for conditional mechanics,
|
||||
Each source supplies the value columns required by its progression:
|
||||
|
||||
- Standard and exotic Talents show Tier I and Tier II.
|
||||
- OS Protocol Talents show a base value and may scale an outcome through the
|
||||
protocol's zero-to-five upgrade expression.
|
||||
- Skill Chip Talents show minimum and maximum values.
|
||||
- Specialization tree ranks show the rank's base value.
|
||||
|
||||
The editor is one layered control surface. Start with a compact program heading
|
||||
and the explicit `READY`, `REQUIRES ASSUMPTIONS`, or `CAPTURED ONLY` state.
|
||||
Follow it with Builder Controls, Recipe Starter, State Pools, ordered event
|
||||
branches, ordered outcomes, and the generated read-only script. Use connected
|
||||
panels and restrained borders to preserve the hierarchy; do not present the
|
||||
typed graph as an undifferentiated form.
|
||||
|
||||
The direct-event picker reads the 19 normalized events from the code-defined
|
||||
event registry. Use searchable single-assignment because the vocabulary exceeds
|
||||
the compact segmented-choice limit. Each branch presents its event, match
|
||||
policy and parameters, optional cooldown, state mutations, and outcomes.
|
||||
Recipe-generated predicates and weights remain visible in the generated
|
||||
script. State rows expose label, agent or target scope, initial value, bounds,
|
||||
best-case value, and optional expiry. Outcome rows expose kind, target scope,
|
||||
Attribute or resource when applicable, value basis, state scaling, phase, and
|
||||
every source-specific value column. The Value Model control supports static
|
||||
values, event fields, reducer output, source-defined scenario controls, and OS
|
||||
Protocol upgrade scaling where the source permits it.
|
||||
|
||||
Action Family recipes are optional authoring starters. Present the recipe
|
||||
catalog as a searchable assignment with only the parameters required by the
|
||||
selected family. `ADD RECIPE BRANCH` copies typed branches into the current
|
||||
source program, where authors may edit its exposed branch, state, and outcome
|
||||
controls. The recipe label records provenance only. `REPLACE PROGRAM` requires
|
||||
an inline confirmation that states all existing branches will be discarded.
|
||||
|
||||
Builder Controls define source-specific advanced scenario assumptions. Authors
|
||||
choose toggle, slider, or numeric input and provide a label, Agent guidance,
|
||||
default value, best-case value, and numeric bounds when applicable. Group these
|
||||
controls behind the builder's advanced scenario surface. Maximum Potential
|
||||
uses best-case values. Custom Scenario uses saved Agent values. A required
|
||||
cadence or environmental value with no supplied assumption keeps the mechanic
|
||||
out of the calculation and displays `REQUIRES ASSUMPTIONS`; the editor and
|
||||
runtime never invent a cadence.
|
||||
|
||||
Use `--shd-model-surface` and `--shd-model-border` for mechanic programs,
|
||||
calculation revisions, and field calibration. The blue information rail marks
|
||||
modeled behavior. Orange remains reserved for selection and activation. Every
|
||||
effect card names its trigger, duration, maximum stacks, and value per stack in
|
||||
text so the mechanic remains clear without color.
|
||||
modeled behavior. Orange remains reserved for selection and activation. Name
|
||||
events, branches, state, cooldowns, durations, stack limits, outcomes, phases,
|
||||
and per-stack values in text so the model remains legible without color.
|
||||
|
||||
The loadout builder gives each unlocked conditional effect three calculation
|
||||
modes:
|
||||
At narrow widths, stack panels, branch controls, state rows, variant columns,
|
||||
and outcomes without changing their order. Keep add, remove, replace, and help
|
||||
controls at least 44 pixels tall. Every disclosure and confirmation exposes
|
||||
its state to assistive technology. Focus remains in the active field when the
|
||||
generated script refreshes, and reduced-motion preferences remove expansion
|
||||
and replacement transitions.
|
||||
|
||||
#### Generated mechanic script
|
||||
|
||||
The shared `PseudoScript` component gives authors and builders a readable
|
||||
transcription of the typed mechanic or combat calculation. The typed event,
|
||||
predicate, reducer, state-pool, outcome, and calculation-stage data remain
|
||||
authoritative. The interface generates the script from that data; authors do
|
||||
not edit or execute the displayed text.
|
||||
|
||||
Render generated script on `--shd-model-surface` with
|
||||
`--shd-model-border`, a blue information rail, restrained green syntax
|
||||
keywords, line numbers, and the shared monospaced typeface. Give the panel an
|
||||
explicit `GENERATED SCRIPT · READ ONLY` label and show its calculation
|
||||
readiness in text. Reserve orange for adjacent actions and selected controls.
|
||||
Do not style the panel as an editable textarea or show a caret, resize handle,
|
||||
or save action.
|
||||
|
||||
Use semantic code content inside the panel. Treat line numbers as structural
|
||||
decoration and ensure assistive technology reads each statement once. Preserve
|
||||
indentation and keep type at the telemetry floor. Long statements may wrap at
|
||||
token boundaries or use horizontal scrolling on narrow widths. Keep the panel
|
||||
within its parent grid with `min-width: 0`. Script regeneration must not move
|
||||
focus or announce the complete script after each field change. Place validation
|
||||
and readiness messages beside the panel with ordinary status semantics.
|
||||
|
||||
Use the shared `MechanicLanguageHelp` control wherever an author can configure
|
||||
mechanics or calculation stages. The compact `SCRIPT REFERENCE` button opens a
|
||||
native help dialog with syntax, event, timing, state, and outcome references.
|
||||
Long registry-level references may use a labeled disclosure with the same
|
||||
content. The help trigger remains near the generated preview so authors do not
|
||||
need to leave the editor to interpret it. Point every full-reference action to
|
||||
`/isac/mechanic-reference`, with a stable section anchor when the source has a
|
||||
specific topic. Do not point full-reference actions to collapsed same-page
|
||||
anchors.
|
||||
|
||||
Help triggers and disclosure summaries use native button semantics,
|
||||
focus-visible treatment, and explicit expanded or dialog state. Opening a
|
||||
dialog moves focus to its close control; Escape and the close action dismiss
|
||||
it and return focus to the trigger. On mobile, the dialog fits the viewport,
|
||||
scrolls its body, and keeps its close action available. Reduced-motion
|
||||
preferences remove dialog and disclosure transitions. Syntax color and motion
|
||||
never carry meaning without text.
|
||||
|
||||
#### Mechanic reference surface
|
||||
|
||||
`/isac/mechanic-reference` is the dedicated read surface for the mechanic and
|
||||
combat-calculation languages. It contains no mutation controls. Give the page a
|
||||
compact section index beside the reference body and keep that index sticky when
|
||||
the available width and viewport height support it. Assign a stable heading
|
||||
anchor to each major section so editor dialogs can link to the relevant
|
||||
definition.
|
||||
|
||||
Present bounded syntax, state, phase, outcome, and calculation-stage
|
||||
vocabularies as connected reference matrices with shared borders and aligned
|
||||
columns. Generate the 19-event registry and Action Family recipe catalog from
|
||||
code-defined metadata so the reference matches the available editor controls.
|
||||
Explain that events are runtime contracts and recipes only seed editable source
|
||||
branches. Pair complex mechanics with a worked `PseudoScript` example. Keep
|
||||
labels and descriptions visible; color, abbreviations, and script keywords
|
||||
cannot carry the explanation alone.
|
||||
|
||||
Include a live-searchable Attribute variable glossary sourced from the active
|
||||
ISAC Attribute registry. Search matches Attribute names, stored descriptions,
|
||||
types, categories, calculation types, units, source ranges, and caps. Display
|
||||
each stored Attribute description verbatim. Show type, category, calculation
|
||||
type, unit, applicable Gear, Weapon, and Skill Chip ranges, and optional cap as
|
||||
supporting metadata. Mark a missing description as `DOCUMENTATION NEEDED` and
|
||||
link authorized authors to the Attribute record; do not generate substitute
|
||||
copy. Search operates on the full active glossary before any result limit and
|
||||
keeps its visible label, clear action, keyboard focus, and textual result count.
|
||||
|
||||
Section-index links and anchored headings use visible keyboard focus. In-page
|
||||
navigation must place the target below the application header. At narrow
|
||||
widths, move the index into document flow above the content and stack reference
|
||||
sections in one column. Allow connected matrices to scroll within their own
|
||||
boundaries, and prevent horizontal page overflow. Reduced-motion preferences
|
||||
remove smooth anchor scrolling and sticky-state transitions.
|
||||
|
||||
#### Builder calculation modes
|
||||
|
||||
The loadout builder places one required two-option `SegmentedChoice` above
|
||||
combat assumptions. The persisted `maximum` and `custom` values use these
|
||||
visible labels:
|
||||
|
||||
- `MAXIMUM POTENTIAL` calculates a configured ceiling. It applies conditional
|
||||
effects at peak state and treats selected abilities as firing on cooldown
|
||||
against their maximum configured target count.
|
||||
- `CUSTOM SCENARIO` exposes encounter assumptions and source-defined advanced
|
||||
controls for a player-defined scenario.
|
||||
|
||||
New loadouts select `MAXIMUM POTENTIAL`. The interface labels Maximum results
|
||||
as a modeled ceiling so players do not read them as typical encounter
|
||||
performance. Maximum hides granular assumption fields without deleting their
|
||||
saved values. Returning to Custom restores those values.
|
||||
|
||||
Custom mode gives each unlocked conditional effect three state controls:
|
||||
|
||||
- `OFF` excludes the effect.
|
||||
- `PEAK` applies its configured maximum stacks.
|
||||
@@ -1868,17 +2011,27 @@ modes:
|
||||
reload time, hit rate, firing activity, and encounter duration.
|
||||
|
||||
Users may override encounter assumptions on one effect without changing the
|
||||
global combat profile. The effect card shows the applied stack state beside the
|
||||
mode. On mobile, assumption fields and effect controls stack into full-width
|
||||
44-pixel targets.
|
||||
global Custom profile. Open the advanced scenario surface to show only the
|
||||
toggle, slider, and numeric controls defined by that effect's owning source.
|
||||
The effect card shows uptime, activation count, and applied stack state beside
|
||||
the mode. A mechanic that needs an undefined cadence or another missing
|
||||
scenario input displays `REQUIRES ASSUMPTIONS`; the builder withholds its
|
||||
calculated contribution until the author or player supplies that input.
|
||||
|
||||
Maximum and Custom use radio semantics, an explicit selected label, keyboard
|
||||
arrow navigation, and the standard orange selected rail. Results repeat the
|
||||
active calculation mode in text. On mobile, the global mode control and Custom
|
||||
assumption fields stack into full-width targets of at least 44 pixels.
|
||||
Mode changes use the standard pressed feedback; reduced-motion preferences
|
||||
remove transitions without hiding the state change.
|
||||
|
||||
Combat result panels show normal, critical, headshot, and critical-headshot
|
||||
values with burst, sustained, and encounter DPS. Conditional stack telemetry
|
||||
lists the mode, average and peak stacks, ending stacks, buildup time, and
|
||||
maintained state that produced the result. A result with missing equipment,
|
||||
Attribute bindings, rules, or assumptions displays `INSUFFICIENT DATA` and a
|
||||
concrete remediation list. The interface withholds combat numbers until it has
|
||||
the required inputs.
|
||||
lists the mode, uptime, activations, average and peak stacks, ending stacks,
|
||||
buildup time, and maintained state. A result with missing equipment, Attribute
|
||||
bindings, rules, or assumptions displays `INSUFFICIENT DATA` and a concrete
|
||||
remediation list. The interface withholds combat numbers until it has the
|
||||
required inputs.
|
||||
|
||||
### Specialization loadout composer
|
||||
|
||||
@@ -1893,10 +2046,16 @@ ranks remain visible with their lock state. The builder permits a row after the
|
||||
user buys every available Rank 1 and Rank 2 in preceding rows and enforces the
|
||||
49-point limit. Cost telemetry lists Credits and components beside each rank.
|
||||
|
||||
Saved loadouts store focus, node ranks, nine Skill Chips, effect modes, and
|
||||
combat assumptions. The builder accepts only the current complete structure.
|
||||
Invalid local drafts are discarded; invalid server records are unavailable and
|
||||
removed through a backed-up database migration.
|
||||
Each ability panel exposes one compact activation control: Off, On Cooldown, or
|
||||
Custom Rate. Custom Rate adds uses per minute. Every enabled
|
||||
ability has its own target count. Skill result cards show the ability name,
|
||||
activation count, single-target DPS, total-target DPS, and a combined summary.
|
||||
They state that Skills can critically hit and multi-shot but cannot headshot.
|
||||
|
||||
Saved loadouts store focus, node ranks, nine Skill Chips, conditional modes,
|
||||
encounter assumptions, and per-ability activation profiles. The builder accepts
|
||||
only the current complete structure. Invalid local drafts are discarded;
|
||||
invalid server records are removed through a backed-up database migration.
|
||||
|
||||
### Calculation revision controls
|
||||
|
||||
@@ -1906,6 +2065,14 @@ requires `calculation.publish`, an explicit review state, and a confirmation
|
||||
that saved builds will recalculate. Successful activation closes the
|
||||
confirmation surface and records the revision in the audit history.
|
||||
|
||||
Keep weapon and Skill Attribute profiles in separate compact registries inside
|
||||
the same revision editor. A Skill profile shows the Attribute, one of the
|
||||
bounded Skill stages, Add or Multiply, and its weight. Use searchable
|
||||
assignment for the ten-stage vocabulary and a segmented control for the
|
||||
two-value operator. Reject duplicate Attribute and stage pairs. Revision
|
||||
cloning, proposal review, publication evidence, and audit snapshots must
|
||||
include both profile registries.
|
||||
|
||||
Calibration cases pair a loadout snapshot with measured hit and timing values.
|
||||
Ready cases require the four hit values, magazine time, and reload time.
|
||||
Assisted suggestions create a draft revision for review and leave activation
|
||||
|
||||
+278
-119
@@ -1,8 +1,8 @@
|
||||
# SHD.build architecture
|
||||
|
||||
The project is built in vertical slices.
|
||||
The team builds the project in vertical slices.
|
||||
|
||||
## Planned stack
|
||||
## Application stack
|
||||
|
||||
- SvelteKit 2 / Svelte 5 with TypeScript
|
||||
- Embedded Turso Database via `@tursodatabase/database` for durable application data
|
||||
@@ -18,14 +18,13 @@ The project is built in vertical slices.
|
||||
- Editor: manage builder source data.
|
||||
- Admin: manage users, roles, source data, and audit history.
|
||||
|
||||
Server code checks authorization for each mutation. Hiding an admin link does
|
||||
not grant authorization.
|
||||
Server code checks authorization for each mutation. UI visibility has no effect
|
||||
on server authorization.
|
||||
|
||||
Weapon and gear range calculations must preserve unrounded decimal endpoints
|
||||
and follow the empirically validated progression rules in
|
||||
[`STAT_LEVEL_SCALING.md`](STAT_LEVEL_SCALING.md). In particular, leveling is
|
||||
linear rather than compounded and game-matching integer values are truncated
|
||||
only at the presentation boundary.
|
||||
Weapon and gear range calculations must preserve decimal endpoints
|
||||
and follow the tested progression rules in
|
||||
[`STAT_LEVEL_SCALING.md`](STAT_LEVEL_SCALING.md). Leveling is linear rather than
|
||||
compounded. The presentation layer truncates game-matching integer values.
|
||||
|
||||
Local credentials use Argon2id PHC strings with a unique random salt per
|
||||
password. Current work factors meet OWASP's 19 MiB / 2 iteration / single-lane
|
||||
@@ -40,7 +39,7 @@ Turso Cloud, libSQL HTTP, remote replicas, auth tokens, or synchronization.
|
||||
The database defaults to `./data/shd-build.db`. Production deployments must
|
||||
provide a persistent writable filesystem and can override the location with
|
||||
`TDR_DATABASE_PATH`. This rules out ephemeral serverless filesystems unless a
|
||||
persistent volume is attached.
|
||||
deployment attaches a persistent volume.
|
||||
|
||||
## Site launch controls
|
||||
|
||||
@@ -94,7 +93,7 @@ closed.
|
||||
7. Admin editors, validation, audit log, and data import/export.
|
||||
# Administrator bootstrap
|
||||
|
||||
The first successfully authenticated user is promoted to `admin` if the
|
||||
The authentication service promotes the first authenticated user to `admin` if the
|
||||
database does not contain an administrator. Promotion uses one conditional
|
||||
database update so concurrent first sign-ins cannot both become administrators.
|
||||
Once an administrator exists, later sign-ins never alter roles.
|
||||
@@ -117,7 +116,7 @@ npm run db:backup:production
|
||||
```
|
||||
|
||||
The scripts write versioned JSON documents beneath `data/backups/` by default.
|
||||
That directory is ignored by Git because backups contain private user data,
|
||||
Git ignores that directory because backups contain private user data,
|
||||
including password hashes.
|
||||
|
||||
To restore, first create an empty database and apply the schema. Then run:
|
||||
@@ -152,30 +151,30 @@ specific action, target entity, timestamp, and useful before/after evidence.
|
||||
The audit registry is read-only and requires `audit.view`; the seeded Auditor
|
||||
role grants that permission without granting mutation capabilities.
|
||||
|
||||
Audit history is immutable. “Revert” is implemented as a new compensating
|
||||
Audit history is immutable. The server implements “Revert” as a new compensating
|
||||
mutation rather than deletion or modification of the original event:
|
||||
|
||||
1. The operator must independently hold `audit.revert`.
|
||||
2. The original action must be explicitly supported and contain a usable
|
||||
1. The operator must hold `audit.revert` in addition to any other access.
|
||||
2. The reversion registry must support the original action and the event must contain a usable
|
||||
before-snapshot.
|
||||
3. The UI requires a second, explicit confirmation.
|
||||
4. The server reloads the target and compares it with the original
|
||||
after-snapshot, ignoring bookkeeping timestamps. A mismatch indicates newer
|
||||
work and blocks automatic compensation.
|
||||
5. Referenced roles, permissions, and relationships are revalidated before
|
||||
restoration. Restoring administrator authority additionally requires full
|
||||
5. The server revalidates referenced roles, permissions, and relationships before
|
||||
restoration. Restoring administrator authority also requires full
|
||||
administrative access.
|
||||
6. The server restores the previous state and appends an `audit.reverted` event
|
||||
whose target is the original audit-event ID.
|
||||
7. A reverted event cannot be reverted again.
|
||||
7. The server rejects a second reversion of the same event.
|
||||
|
||||
# Moderated game-data contributions
|
||||
|
||||
ISAC data access is split into `data.view`, `data.propose`, `data.manage`, and
|
||||
ISAC data access uses `data.view`, `data.propose`, `data.manage`, and
|
||||
`data.approve`. Data Viewers can inspect registries. Data Contributors can submit
|
||||
the same editor forms, but the request is serialized into `data_change_proposals`
|
||||
instead of mutating canonical tables. Data Oversight reviews the queue and must
|
||||
explicitly confirm approval or rejection.
|
||||
the same editor forms, but the server serializes each request into
|
||||
`data_change_proposals` instead of mutating canonical tables. Data Oversight
|
||||
reviews the queue and must confirm approval or rejection.
|
||||
|
||||
Approval replays the stored form through its original SvelteKit server action.
|
||||
This preserves canonical validation, relational updates, icon processing, and the
|
||||
@@ -190,12 +189,18 @@ Data Oversight combines direct-write access with queue review. New ISAC data
|
||||
modules must use the shared moderation interception path and audit both the final
|
||||
mutation and proposal lifecycle.
|
||||
|
||||
Every authenticated, active registered agent receives `isac.access`,
|
||||
Mechanic programs remain part of their owning source record. Talent, OS
|
||||
Protocol, Skill Chip, and Specialization proposals carry the complete typed
|
||||
program with the rest of the source payload. Oversight reviews and approves
|
||||
that program through the source module's canonical validation path. There is
|
||||
no standalone Trigger proposal module or pending Trigger dependency.
|
||||
|
||||
Each authenticated, active registered agent receives `isac.access`,
|
||||
`data.view`, and `data.propose` as baseline permissions in the authorization
|
||||
layer. This baseline is intentionally implicit rather than a removable role
|
||||
assignment, so it applies consistently to existing users and every account
|
||||
creation method. Registered agents can inspect live source data and submit
|
||||
moderated proposals, but cannot directly mutate canonical records, review the
|
||||
layer. The authorization layer grants this baseline without a removable role
|
||||
assignment, so existing users and each account-creation method receive the same
|
||||
access. Registered agents can inspect live source data and submit
|
||||
moderated proposals, but cannot mutate canonical records, review the
|
||||
queue, or access unrelated ISAC operations without additional permissions.
|
||||
Unsupported destructive identity operations, account deletion, incomplete
|
||||
snapshots, stale targets, and events whose dependencies no longer exist are
|
||||
@@ -204,7 +209,7 @@ specialized workflow rather than inferred database writes.
|
||||
|
||||
# System metrics
|
||||
|
||||
ISAC uses `/isac` as its canonical route namespace. The server permanently
|
||||
ISAC uses `/isac` as its canonical route namespace. The server
|
||||
redirects legacy `/admin` URLs to their matching `/isac` location so old
|
||||
notifications and external bookmarks remain usable.
|
||||
|
||||
@@ -217,10 +222,10 @@ provide application record volumes.
|
||||
|
||||
The interface refreshes on demand and may poll every ten seconds while the
|
||||
operator keeps auto-refresh enabled. CPU and event-loop values are deltas from
|
||||
the previous server-side sample, so the first or infrequently requested sample
|
||||
is directional rather than a monitoring-grade time series. Production alerting
|
||||
and historical analysis should eventually use a dedicated external telemetry
|
||||
system. This surface deliberately omits secrets, environment-variable values,
|
||||
the previous server-side sample, so the first sample and samples separated by
|
||||
long gaps provide direction rather than a monitoring-grade time series. Production alerting
|
||||
and historical analysis should use a dedicated external telemetry
|
||||
system. This surface omits secrets, environment-variable values,
|
||||
and full database paths.
|
||||
|
||||
The same surface reports remove.bg paid credits and free API calls as separate
|
||||
@@ -234,27 +239,27 @@ last known balance and never expose the API key or raw response body.
|
||||
|
||||
# Weapon-owned exotic talents
|
||||
|
||||
Standard weapon talent pools remain globally reusable and classified by Talent
|
||||
1 / Top or Talent 2 / Bottom. An exotic talent is different: one exotic weapon
|
||||
owns one dedicated talent, referenced by `weapons.exotic_talent_id`.
|
||||
Standard weapon talent pools remain reusable across weapons and use Talent 1 /
|
||||
Top or Talent 2 / Bottom. One exotic weapon owns each exotic talent through
|
||||
`weapons.exotic_talent_id`.
|
||||
|
||||
The weapon editor creates and updates the underlying normalized `talents`,
|
||||
`talent_tiers`, trigger links, effect links, description template, and Exotic
|
||||
weapon scope together with the weapon. Server validation rejects an exotic
|
||||
talent ID not already owned by the edited weapon and rejects any talent shared
|
||||
by another weapon. Converting a weapon back to standard clears the relationship
|
||||
and archives its now-unowned exotic talent. Exotic talent creation and editing
|
||||
are rejected by the shared Talent Registry so ownership cannot be bypassed.
|
||||
`talent_tiers`, description template, and typed conditional rule together with
|
||||
the weapon. Server validation rejects an exotic talent ID owned by another
|
||||
weapon and rejects any shared Talent. Converting a weapon back to standard
|
||||
clears the relationship and archives its now-unowned exotic Talent. The shared
|
||||
Talent Registry rejects exotic Talent creation and editing so contributors
|
||||
cannot bypass weapon ownership.
|
||||
|
||||
# OS Protocol progression
|
||||
|
||||
OS Protocols use dedicated normalized tables because their talent progression
|
||||
has six calculated states (base plus five upgrades) rather than the shared
|
||||
two-tier talent model. Each protocol owns one `os_protocol_primary_effects`
|
||||
record and one `os_protocol_talents` record. Talent effects and reusable
|
||||
triggers live in their respective join tables.
|
||||
record and one `os_protocol_talents` record. Each protocol Talent owns its
|
||||
mechanic program through the shared conditional-effect tables.
|
||||
|
||||
The three secondary attributes are normalized separately. One
|
||||
Dedicated profile tables normalize the three secondary attributes. One
|
||||
`os_protocol_secondary_profiles` record exists for each configured quality +
|
||||
attribute-type combination, with its three fixed stat/value pairs in
|
||||
`os_protocol_secondary_effects`. Every matching protocol inherits that profile;
|
||||
@@ -275,16 +280,17 @@ single slot type and one or more compatible base weapon categories through
|
||||
and the slot to exist on the equipped weapon at its selected tier.
|
||||
|
||||
Exotic Weapon Mods instead reference one `exotic_weapon_id`. They do not carry
|
||||
regular category compatibility, are considered permanently equipped, and may
|
||||
only be leveled. They do not use quality profiles, random primary rolls,
|
||||
secondary pools, or regular Mod Effects. Their canonical contributions are
|
||||
fixed attribute references with explicit level-1 and level-20 values in
|
||||
`weapon_mod_exotic_attributes`; intermediate values interpolate linearly.
|
||||
regular category compatibility. The builder treats them as permanent equipment
|
||||
and lets the user change only their level. They do not use quality profiles,
|
||||
random primary rolls, secondary pools, or regular Mod Effects. Their canonical
|
||||
contributions are fixed attribute references with explicit level-1 and level-20
|
||||
values in `weapon_mod_exotic_attributes`; intermediate values use linear
|
||||
interpolation.
|
||||
|
||||
All regular Weapon Mods permit Firepower, Toughness, or Engineering as a
|
||||
builder-time primary choice. `weapon_mod_quality_values` stores the shared
|
||||
level-1 and level-20 primary roll endpoints for each quality; primary values
|
||||
interpolate linearly from levels 1–20.
|
||||
use linear interpolation from levels 1–20.
|
||||
|
||||
`weapon_mod_secondary_options` is the shared pool from which a build selects
|
||||
two distinct secondary attributes. Every option owns a minimum and maximum at
|
||||
@@ -298,7 +304,7 @@ values in `weapon_mod_effect_quality_values`.
|
||||
Gear Mod definitions are standard-quality records only; there is no exotic
|
||||
Gear Mod branch. Every definition supplies primary roll ranges for Standard,
|
||||
Specialized, Superior, and High-end quality at Levels 1 and 20. Values between
|
||||
those endpoints scale linearly. A build instance selects one primary attribute
|
||||
those endpoints use linear interpolation. A build instance selects one primary attribute
|
||||
from Firepower, Toughness, Engineering, Health, or Armor.
|
||||
|
||||
The two secondary slots draw distinct attributes from one shared option pool.
|
||||
@@ -306,8 +312,8 @@ Each available secondary attribute stores its own minimum and maximum for all
|
||||
four qualities. Gear tier determines capacity without per-item configuration:
|
||||
T0 gear has one Gear Mod slot; T1 and T2 gear have two.
|
||||
|
||||
Canonical data is stored in `gear_mods`, `gear_mod_quality_values`,
|
||||
`gear_mod_secondary_options`, and `gear_mod_secondary_quality_values`.
|
||||
The `gear_mods`, `gear_mod_quality_values`, `gear_mod_secondary_options`, and
|
||||
`gear_mod_secondary_quality_values` tables store canonical data.
|
||||
Successful mutations use `gear_mod.created`, `gear_mod.updated`,
|
||||
`gear_mod.archived`, and `gear_mod.unarchived` audit actions. Contributor
|
||||
submissions use the `gearmods` proposal module and remain non-canonical until
|
||||
@@ -317,16 +323,16 @@ approved by Oversight.
|
||||
|
||||
Skill Chip sets support Superior and High-end chip instances. Each set owns one
|
||||
2-piece bonus, distinct primary and secondary stat-option pools, and one
|
||||
3-piece talent with reusable trigger links and normalized effect rows. Primary
|
||||
and secondary options reference active attributes that define Skill Chip
|
||||
minimum and maximum roll values; a configured chip rolls one primary and two
|
||||
distinct secondary stats from those separate pools.
|
||||
3-piece Talent with a typed conditional rule. Primary and secondary options
|
||||
reference active Attributes that define Skill Chip minimum and maximum roll
|
||||
values. A configured chip rolls one primary and two distinct secondary stats
|
||||
from those pools.
|
||||
|
||||
Every active Skill Chip definition belongs exclusively to one active
|
||||
specialization ability through `skill_chip_sets.specialization_ability_id`.
|
||||
An ability has capacity for exactly three active definitions. The save and
|
||||
restore actions enforce that capacity, and the foreign key is required for
|
||||
every row. A specialization focus is builder-ready only when each of its three
|
||||
Each active Skill Chip definition belongs to one active specialization ability
|
||||
through `skill_chip_sets.specialization_ability_id`. An ability has capacity for
|
||||
three active definitions. The save and restore actions enforce that capacity,
|
||||
and the schema requires the foreign key for each row. A specialization focus is
|
||||
builder-ready only when each of its three
|
||||
assigned abilities has all three active Skill Chip definitions. Skill Chip
|
||||
mutations refresh readiness for focuses that reference both the previous and
|
||||
resulting ability.
|
||||
@@ -337,48 +343,176 @@ three, a configured minimum and maximum resolve as
|
||||
`minimum + (maximum − minimum) × h / 3`. Zero High-end chips therefore produce
|
||||
the minimum, while three produce the maximum. The editor stores endpoints and
|
||||
previews all four states, preventing duplicated tier data from diverging.
|
||||
Skill Chip mutations, owned relationships, and safe icon metadata are captured
|
||||
in the `game_data` audit stream.
|
||||
The `game_data` audit stream captures Skill Chip mutations, owned relationships,
|
||||
and safe icon metadata.
|
||||
|
||||
# Specialization combat effects and loadout state
|
||||
# Mechanic programs and loadout state
|
||||
|
||||
`specialization_combat_effects` stores reusable effect identity and description
|
||||
within one Specialization. A node rank attaches that identity through
|
||||
`specialization_tree_rank_combat_effects` and supplies the trigger count,
|
||||
trigger window, duration, stack limit, and stack gain. The first supported
|
||||
lifecycle uses an enemy-hit counter that resets after a proc. Each stack gain
|
||||
refreshes one shared duration, and expiry clears all stacks.
|
||||
Mechanic programs belong to the record whose behavior they describe. One
|
||||
`conditional_effect_rules` row owns the program for one standard or exotic
|
||||
Talent, OS Protocol Talent, Skill Chip Talent, or Specialization tree rank. The
|
||||
`source_type` and `source_id` pair identifies that owner. No standalone Trigger
|
||||
record or shared Trigger relationship participates in execution.
|
||||
|
||||
`specialization_tree_rank_combat_modifiers` maps each attachment to one or more
|
||||
Attributes with a value per stack. This split lets ranks share effect language
|
||||
while changing their trigger and values. Specialization mutations capture the
|
||||
attachment and modifier sets in the `game_data` audit event. Contributors can
|
||||
submit effect definitions and node attachments through the existing
|
||||
Specialization proposal workflow.
|
||||
Each source supplies a fixed value-variant contract:
|
||||
|
||||
Loadout schema version 2 stores one focus, the selected rank for each tree node,
|
||||
nine Skill Chips, conditional-effect modes, and encounter assumptions. Each of
|
||||
the three focus abilities owns three chip positions. Runtime readers accept
|
||||
only the exact version 2 structure. Local drafts, saved builds, shared builds,
|
||||
and calibration snapshots reject older or partial structures instead of
|
||||
repairing them. Database migration removes obsolete snapshots after the
|
||||
required environment backup.
|
||||
- Standard and exotic Talents require Tier I and Tier II values.
|
||||
- OS Protocol Talents store a base value. An outcome may use an expression that
|
||||
reads `equipment.protocolTalentUpgrades`, from zero through five, so selected
|
||||
values can scale to twice the base at upgrade five.
|
||||
- Skill Chip Talents store minimum and maximum values for quality composition
|
||||
interpolation.
|
||||
- Specialization tree-rank effects store the rank's base value.
|
||||
|
||||
The rule row stores the script version, source-defined scenario-input controls,
|
||||
configuration state, and one of three simulation-readiness states:
|
||||
|
||||
- `ready`: the runtime has enough typed data to calculate the mechanic.
|
||||
- `requires_assumptions`: the mechanic needs one or more scenario inputs before
|
||||
the runtime can include it.
|
||||
- `captured_only`: ISAC preserves the authored mechanic, but the runtime cannot
|
||||
calculate it.
|
||||
|
||||
The code-defined `MECHANIC_EVENT_REGISTRY` is the event authority. Its 19
|
||||
normalized events are `shot_fired`, `weapon_hit`, `skill_deployed`,
|
||||
`skill_hit`, `agent_hit`, `health_damage_taken`, `damage_dealt`,
|
||||
`enemy_killed`, `assist`, `healing_applied`, `extra_health_granted`,
|
||||
`movement_snapshot`, `proximity_snapshot`, `firing_started`, `firing_stopped`,
|
||||
`reload_started`, `reload_completed`, `weapon_swapped`, and `tick`. Event
|
||||
details such as target, distance, critical state, source, movement, and nearby
|
||||
counts travel as typed event values.
|
||||
|
||||
The optional Action Family catalog provides authoring recipes for common
|
||||
mechanics. Applying a recipe copies its typed scenario inputs, state pools, and
|
||||
clauses into the source-owned program. Those branches become editable
|
||||
authoritative data; the recipe key remains provenance, not a runtime
|
||||
dependency. Adding another recipe appends branches. Replacing a program with a
|
||||
recipe requires confirmation because replacement discards the current branch
|
||||
graph.
|
||||
|
||||
The program graph uses three child tables:
|
||||
|
||||
- `conditional_effect_state_pools` defines agent- or target-scoped flags,
|
||||
counts, stacks, durations, scalar values, marks, and resources. Each pool
|
||||
owns its bounds, expiry policy, refresh policy, and best-case value.
|
||||
- `conditional_effect_clauses` listens for one of the 19 events. A clause owns
|
||||
a typed predicate, reducer, optional cooldown, optional weight expression,
|
||||
state mutations, and optional recipe provenance. Reducers convert event
|
||||
streams into counts, distinct or consecutive matches, sliding windows,
|
||||
durations, intervals, or derived values. Mutations can set, add, consume,
|
||||
clear, derive, or transfer state.
|
||||
- `conditional_effect_outcomes` applies Attribute modifiers, direct damage,
|
||||
restoration, resource costs, or markers. Each outcome names its target scope,
|
||||
value basis, optional resource or Attribute, combat timing, optional state
|
||||
band, and phase: `on_event`, `after_event`, `on_enter`, `on_exit`, or
|
||||
`while_active`. One typed value or expression exists for every variant
|
||||
required by the owning source. The common value models are static values,
|
||||
event-field values, reducer output, source-defined scenario values, and OS
|
||||
Protocol upgrade scaling.
|
||||
|
||||
The generic runtime in `src/lib/calculations/mechanic.ts` processes combat events
|
||||
in timestamp order. Predicates decide whether an event enters a clause. Reducers
|
||||
convert event streams into activations or derived values. The runtime applies
|
||||
state mutations, enforces pool bounds and expiry, emits outcomes in phase order,
|
||||
and records telemetry for each activation.
|
||||
|
||||
Periodic behavior requires an interval in the reducer. The runtime does not
|
||||
infer a one-second cadence from missing data. A mechanic with an unknown cadence
|
||||
uses `requires_assumptions`, identifies the missing input, and stays out of the
|
||||
calculation until an operator or builder scenario supplies it.
|
||||
|
||||
The runtime derives a read-only pseudo-language listing from the typed program.
|
||||
ISAC and the builder use that listing to explain events, predicates, reducers,
|
||||
state changes, phases, and formulas. No route accepts the generated text as
|
||||
input, and no server process executes it. Operators edit structured fields; the
|
||||
formatter regenerates the listing after each change.
|
||||
|
||||
Source authors define the builder controls required by their mechanic as typed
|
||||
toggle, slider, or numeric scenario inputs. Each input records its label,
|
||||
guidance, bounds when applicable, default value, and best-case value. These
|
||||
controls appear only in advanced scenario configuration. Maximum mode supplies
|
||||
best-case values. Custom mode uses the values saved with the loadout. A
|
||||
mechanic with an undefined required assumption remains excluded and reports
|
||||
`REQUIRES_ASSUMPTIONS`.
|
||||
|
||||
Loadout schema version 4 stores one focus, selected tree ranks, nine Skill
|
||||
Chips, a unified conditional-effect state map, encounter assumptions,
|
||||
per-ability activation controls, and `calculationMode`. Runtime readers accept
|
||||
the exact version 4 structure. A backed-up prototype migration removes drafts,
|
||||
saved builds, and calibration snapshots that use incompatible payloads.
|
||||
|
||||
## Calculation modes
|
||||
|
||||
The builder offers `maximum` and `custom` modes.
|
||||
|
||||
- Maximum mode supplies each scenario input's best-case value, selects peak
|
||||
conditional-effect state, and runs selected abilities on cooldown against
|
||||
their configured target caps. The interface hides granular assumptions in
|
||||
this mode.
|
||||
- Custom mode uses the agent's encounter inputs, effect states, activation
|
||||
rates, target counts, and other supported assumptions. A missing required
|
||||
input produces `REQUIRES_ASSUMPTIONS` rather than a fabricated value.
|
||||
|
||||
Saved and shared loadouts preserve the selected mode. Calculation results label
|
||||
the mode so readers can distinguish a best-case ceiling from a scenario-based
|
||||
estimate.
|
||||
|
||||
## Specialization ability attacks
|
||||
|
||||
`specialization_ability_attacks` stores intrinsic base damage, Blast, Pierce, or
|
||||
Shredding damage, direct or periodic delivery, hit or tick counts, cast time,
|
||||
target cap, and charge behavior. `skill_attribute_calculation_profiles` binds
|
||||
Attributes to the versioned Skill damage and cadence stages. Cooldown Recovery
|
||||
changes charge and activation readiness. Duration changes the number of
|
||||
periodic ticks.
|
||||
|
||||
Periodic delivery waits one configured tick interval before its first tick and
|
||||
excludes ticks at or after the encounter boundary. The Skill engine reevaluates
|
||||
active modifier windows at each delivered hit or tick. A missing tick interval
|
||||
marks the attack as requiring configuration; the engine does not supply a
|
||||
default cadence.
|
||||
|
||||
# Versioned combat calculations
|
||||
|
||||
`calculation_revisions` supplies one active rule set. Draft revisions can
|
||||
change, while active and retired revisions stay immutable.
|
||||
`calculation_revisions` supplies one active rule set. Operators can change draft
|
||||
revisions, while active and retired revisions stay immutable.
|
||||
`calculation_stages` stores the ordered typed pipeline. The base-damage stage
|
||||
holds the first position, and the firing-cycle stage holds the last.
|
||||
`attribute_calculation_profiles` maps an Attribute to a stage with its weight,
|
||||
optional caps, curve, and weapon-category scope.
|
||||
`attribute_calculation_profiles` maps an Attribute to a weapon stage with its
|
||||
weight, optional caps, curve, and weapon-category scope.
|
||||
|
||||
The shared combat engine consumes weapon facts, accumulated Attributes,
|
||||
calculation profiles, and conditional effects. It produces four hit values,
|
||||
burst DPS, reload-aware sustained DPS, encounter DPS, and stack telemetry.
|
||||
Encounter mode walks the expected shot timeline from RPM, magazine size,
|
||||
reload time, hit rate, firing activity, and encounter duration. Peak mode
|
||||
applies maximum stacks, and Off mode excludes the effect.
|
||||
calculation profiles, and mechanic outcomes. It produces four hit values, burst
|
||||
DPS, reload-aware sustained DPS, encounter DPS, and stack telemetry. Custom mode
|
||||
walks the expected shot timeline from RPM, magazine size, reload time, hit rate,
|
||||
configured burst size, pauses between bursts, and encounter duration. It
|
||||
resolves the active Attribute state at each landed shot before calculating that
|
||||
shot's expected damage.
|
||||
|
||||
The builder scales a weapon definition's level-1 damage range to the equipped
|
||||
item level, then the agent selects one damage value inside that valid range.
|
||||
Combat receives `equipped_weapon.damage` as its base damage and consumes that
|
||||
number once. The combat pipeline has no `level_scaled_damage` value and must not
|
||||
apply item-level scaling a second time.
|
||||
|
||||
The generated calculation listing names each typed pipeline stage and its bound
|
||||
Attributes. The listing explains the active revision with statements such as
|
||||
`TAKE equipped_weapon.damage AS base_damage`, `ADD`, `APPLY`, `WEIGHT`, and
|
||||
`RETURN`. The typed stages and profiles remain authoritative. The application
|
||||
neither parses nor executes the listing.
|
||||
|
||||
The Headshot Kill Share assumption marks the matching portion of generated kill
|
||||
events for headshot-kill triggers. Rate of Fire, Magazine Size, and Reload Speed
|
||||
bindings change the firing-cycle calculation. Maximum mode applies maximum
|
||||
state. Custom mode can set an effect to Peak, Encounter, or Off.
|
||||
|
||||
The Skill engine uses a dedicated intrinsic ability-damage model. It supports
|
||||
direct and periodic delivery, critical and multi-shot expectation, target caps,
|
||||
per-ability activation rates, and charge recovery.
|
||||
Skills do not headshot. Dynamic Talent and tree-effect windows apply to each
|
||||
Skill hit at its delivery time. Encounter-triggered Skill modifiers use the
|
||||
primary weapon timeline until the builder supports a combined weapon-rotation
|
||||
model.
|
||||
|
||||
The engine returns `INSUFFICIENT_DATA` with missing requirement keys when a
|
||||
calculation lacks required inputs or an Attribute binding. Callers must render
|
||||
@@ -389,35 +523,60 @@ active revision for each request.
|
||||
hit values, timing values, optional encounter DPS, and the model prediction.
|
||||
Ready cases require the four hit values plus magazine and reload times. The
|
||||
assisted suggestion action compares ready observations with their predictions
|
||||
and creates a draft revision for an operator to review.
|
||||
and creates a draft revision for operator review.
|
||||
|
||||
Rule activation requires `calculation.publish` and an explicit confirmation.
|
||||
Rule activation requires `calculation.publish` and a confirmation.
|
||||
ISAC records draft creation, draft edits, publication, calibration changes, and
|
||||
assisted suggestions under the `calculation_configuration` audit category.
|
||||
ISAC data export and environment synchronization include calculation rules,
|
||||
calibration cases, and Specialization combat-effect tables in dependency order.
|
||||
typed mechanic programs, ability attacks, calibration cases, and their
|
||||
relationships in dependency order.
|
||||
|
||||
## OS Protocol upgrade expressions and health timing
|
||||
|
||||
OS Protocol talents expose zero through five upgrade states. Value expressions
|
||||
reference `equipment.protocolTalentUpgrades` and use the linear multiplier
|
||||
`1 + upgrades / 5`. Base values resolve at upgrade zero, and scalable values
|
||||
reach twice their base at upgrade five. Each outcome chooses whether to use this
|
||||
multiplier, so a fixed resource cost can remain unchanged while restoration and
|
||||
damage increase.
|
||||
|
||||
Happy Survival uses three clauses:
|
||||
|
||||
1. Its proximity clause records the current enemy count within 10 meters.
|
||||
2. Its periodic clause restores
|
||||
`min(enemyCount × 0.5%, 2.5%) × (1 + upgrades / 5)` of maximum Health. The
|
||||
reducer reads the configured interval from an explicit scenario input. The
|
||||
runtime caps applied restoration at missing Health.
|
||||
3. Its `shot_fired` clause consumes 2% of maximum Health, then deals direct
|
||||
damage equal to `0.6% × (1 + upgrades / 5)` of current Health. The
|
||||
`resource_cost` outcome runs first. The damage outcome uses the remaining
|
||||
current Health after that cost, rather than the pre-event Health value.
|
||||
|
||||
At upgrade five, the restoration becomes 1% of maximum Health per nearby enemy
|
||||
up to 5%, and the shot damage becomes 1.2% of current Health. The 2% Health cost
|
||||
does not scale.
|
||||
|
||||
# Game-data icon storage
|
||||
|
||||
Talents, brand sets, OS Protocols, and Skill Chips reference uploaded artwork
|
||||
through the polymorphic `game_data_icons` metadata table. The shared server
|
||||
pipeline accepts transparent SVG, PNG, WebP, and AVIF sources, rejects active
|
||||
or externally referenced SVG content, and uses Sharp’s native worker pool to
|
||||
SVG content and external references, and uses Sharp’s native worker pool to
|
||||
rasterize and normalize each accepted icon to a transparent 256 × 256 WebP.
|
||||
|
||||
Normalized files live beneath the ignored `data/game-icons/` directory and are
|
||||
served by the validated `/icons/game-data/[type]/[id]` endpoint with immutable
|
||||
cache headers and MIME sniffing disabled. ISAC save actions process files
|
||||
Normalized files live beneath the ignored `data/game-icons/` directory. The
|
||||
validated `/icons/game-data/[type]/[id]` endpoint serves them with immutable
|
||||
cache headers and disables MIME sniffing. ISAC save actions process files
|
||||
before mutation, apply upload or removal after record validation, and include
|
||||
safe icon metadata, rather than image bytes, in audit snapshots.
|
||||
|
||||
Icon metadata is optional. Canonical records and contributor proposals may be
|
||||
created without an upload, allowing values and artwork to be contributed in
|
||||
separate dependency-safe changes. Missing artwork is represented at render
|
||||
time by the static `/missing-item-icon.svg` asset through the shared
|
||||
`MISSING_ITEM_ICON_URL` constant and `ItemIcon` component. The placeholder does
|
||||
not enter `game_data_icons`. A later edit or proposal can attach the real icon
|
||||
without recreating the canonical item.
|
||||
created without an upload, which lets contributors submit values and artwork in
|
||||
separate dependency-safe changes. The shared `MISSING_ITEM_ICON_URL` constant
|
||||
and `ItemIcon` component render `/missing-item-icon.svg` for missing artwork.
|
||||
The placeholder does not enter `game_data_icons`. A later edit or proposal can
|
||||
attach the real icon without recreating the canonical item.
|
||||
|
||||
`source_entity_type` and `source_entity_id` link each `game_data_icons` row to a
|
||||
`managed_images` record. Both records share one storage key and one WebP file.
|
||||
@@ -433,14 +592,14 @@ keeps the library metadata and one copy of each file.
|
||||
|
||||
# Oversight notification dispatch
|
||||
|
||||
New Data Change and Avatar Oversight review items are routed only to agents who
|
||||
currently hold `data.approve` or `avatars.review` respectively. Each reviewer
|
||||
chooses Immediate, 15-minute, one-hour, or daily delivery independently for
|
||||
each authorized queue. Immediate alerts are created during submission;
|
||||
consolidated alerts are persisted in `oversight_notification_queue`.
|
||||
The notification router sends Data Change review items to agents who hold
|
||||
`data.approve` and Avatar Oversight review items to agents who hold
|
||||
`avatars.review`. Each reviewer chooses Immediate, 15-minute, one-hour, or
|
||||
daily delivery for each authorized queue. Submission creates Immediate alerts;
|
||||
`oversight_notification_queue` stores consolidated alerts.
|
||||
|
||||
Production must run the idempotent dispatcher once per minute from exactly one
|
||||
scheduler instance:
|
||||
Production must run the idempotent dispatcher once per minute from one scheduler
|
||||
instance:
|
||||
|
||||
```text
|
||||
* * * * * cd /path/to/shd.build && npm run notifications:oversight:production
|
||||
@@ -449,27 +608,27 @@ scheduler instance:
|
||||
The dispatcher groups due rows by reviewer, queue, cadence, and delivery
|
||||
window. Daily rows use the next 10:00 AM wall-clock boundary in
|
||||
`America/New_York`, including daylight-saving transitions. Dispatched rows
|
||||
retain `delivered_at` evidence and are excluded from later selection. Existing
|
||||
retain `delivered_at` evidence, and later queries exclude them. Existing
|
||||
ISAC notification delivery preferences determine optional browser and email
|
||||
fan-out after the consolidated inbox message is created.
|
||||
fan-out after the dispatcher creates the consolidated inbox message.
|
||||
|
||||
## Automated ISAC system messages
|
||||
|
||||
Automated message definitions live in `automated_system_messages` and are
|
||||
managed through ISAC → System Configuration → Automated Messages by agents with
|
||||
`system.notifications.manage`. Edits are recorded under the
|
||||
`system.notifications.manage`. The audit log records edits under the
|
||||
`system_configuration` audit category. Definitions identify a lifecycle event,
|
||||
enabled state, delay in minutes, message content, primary destination, and
|
||||
structured action callouts.
|
||||
|
||||
`account.created` is emitted by password, magic-link, and Discord registration.
|
||||
Password, magic-link, and Discord registration emit `account.created`.
|
||||
The delivery table has a unique message/user/event/event-ID constraint, so the
|
||||
same account creation cannot deliver the Welcome Agent message more than once.
|
||||
The default welcome introduces News, Database, Builds, Guides, Builder, ISAC
|
||||
Contributor Mode, and the SHD Discord community.
|
||||
|
||||
Immediate definitions are delivered in the registration request. Definitions
|
||||
with a delay are persisted in `automated_system_message_deliveries`. Production
|
||||
The registration request delivers Immediate definitions.
|
||||
`automated_system_message_deliveries` stores definitions with a delay. Production
|
||||
must run the delayed dispatcher once per minute:
|
||||
|
||||
```text
|
||||
|
||||
Reference in New Issue
Block a user