Skyveil 2.3.0
==============================================

A client-side addon for World of Warcraft: Forever (Classic+).
It veils Skyborne elves on YOUR client: nameplates, names, chat,
whispers, emotes, tooltips, and target identity.

It also drops chat from players in a guild whose name contains a
needle you add. No needle is set until you add one. Their
nameplates stay. The ignore list is not used, and the other player
is not told.

Filtering is local. It sends nothing to the server except a /who when
you ask and the declines you turn on. If you turn on Guild Command:
Private, it also sends the addon messages you press Send for: to your
guild, its officers, one member, the other guild's master when you
request or remove an alliance link, or (with Alliance Sync linked) the
allied guild master and their delegates. As guild master, it also sends
a guild rank rename you press Send for. If you turn on Layers (Beta), it
also sends what LAYERS (BETA) below says: your Share line on each press,
layer requests, invites, accepts, group leaves, joining and leaving the
SkyveilLayers channel and, as host, the lead pass (PromoteToLeader) of
leave order 3. Nothing else.

Every send site in this release, and nothing else: (a) SkyveilSync's
one-shot -LocalLlmHint / --local-llm-hint, only when you run it, sends
one report's first line, state line and errors once to a model on your
own computer (127.0.0.1, ::1 or localhost), then exits; (b) the
website help bar's Tier 2 bridge to Ollama or llama.cpp on your
computer, only when you turn it on and press Ask; (c) the browser's
built-in model, only when you turn it on (it runs inside your
browser); (d) the /who, decline, Guild Command and Layers sends above.
Hints, /sv ? and /sv debug send nothing. No cloud service is called.


INSTALL
-------
1. Unzip so you have a folder named Skyveil (this folder).
2. Put that folder in Interface/AddOns:

   World of Warcraft\_classic_\Interface\AddOns\Skyveil
   World of Warcraft\_classic_beta_\Interface\AddOns\Skyveil

   Confirm the folder in the Battle.net app. Create AddOns if it
   is missing.

3. Restart the game (a /reload is not enough for a newly copied addon).
4. At character select, click AddOns and enable Skyveil.

Skyveil.toc uses interface 16001, the number Forever addons publish
for client 1.60.1. If the addon shows as out of date, tick
"Load out of date AddOns".


SLASH COMMANDS
--------------
/skyveil and /sv open the options. Every command (also /sv help all):

/sv options — open the options panel
/sv config — open the options in a movable window of its own
/sv stats — blocked-line counts: today, 7 days, 14 days, top channels and
    rules
/sv on — lower the veil
/sv off — raise the veil
/sv toggle — flip on or off
/sv cross on|off — guild master cross next to names (display only, on by
    default)
/sv inspect — race id, file, GUID and guild of your target
/sv status — nearby, Skyborne, guild and rule counts
/sv clearcache — forget remembered Skyborne names and GUIDs
/sv forgetids — forget learned race ids
/sv forgetguilds — forget learned guild names
/sv guild add|remove|list <text> | guild note <text> = <note> | guild expire
    <text> 7|30|90|never — match text inside a guild name; a needle can
    carry a note and an expiry
/sv mute Name — hide that player's chat on this client
/sv unmute Name — undo a hand mute
/sv word add|remove <text> — hide any message containing the text (a rule
    in every channel)
/sv alerts [trigger|output] on|off | alerts <trigger> <output> on|off |
    alerts cooldown N | alert test — alerts on your client only: chat
    line, sound, raid-warning-style screen text, flash; 10 s cooldown, one
    per 2 s (off until you turn them on)
/sv roster on|off|show [n]|find Name|summary|clear — guild join, leave and
    rank log; names kept as salted hashes (off until you turn it on);
    summary counts ranks and recent activity
/sv minimap on|off — show or hide the minimap button
/sv setup [scope=full|names|chat] [gold recruit links lfg nonlatin spam
    repeats minimap] [profile=shared|character] — setup in three steps:
    veil scope, presets, profile mode
/sv groupwarn on|off — a line when a member of a veiled guild joins your
    group (names the guild only)
/sv who — one /who for a guild needle (5 s cooldown)
/sv layers [share on|off|host on|off|off|block Name|unblock Name|cap 1-3]
    — Layers (Beta): open the tab; share, host, off, block a name, host
    invite cap (off until you turn them on)
/sv layerlog — this session's layer events, 200 lines (memory only,
    cleared at logout except a saved debug report's copy)
/sv debug — debug report to copy; Save and reload saves it to the
    SavedVariables file (last 5 kept)
/sv ? <words> | hint <words> — search Skyveil's help on your client;
    prints at most 2 lines, only when you ask
/sv private help — Guild Command: Private (beta, off until you turn it on)
/sv help [page|all] — this list, ten lines a page
/sv rule add word|contains|starts|link|item|wild|nonlatin <text>
    [scope=trade,say,...] [highlight] — add a chat rule
/sv log [n] — show the last blocked lines (memory only)
/sv reveal N — show one blocked line
/sv unblock N — turn off the rule that hid line N, exempt its guild or
    unmute its sender
/sv exemptguild <guild> — never veil a guild by needle (same as unblock on
    its line)
/sv unexempt <guild>|list — remove a guild exemption, or list them
/sv spam off|low|normal|strict — spam filter for public chat
/sv repeats on|off|<seconds> — hide the same line from the same sender
    within the repeat window (30 seconds by default, 5 to 600)
/sv lowlevel N|off — hide whispers from players below level N when their
    level is known
/sv exempt friends|guild|group on|off — who is never hidden by rules
/sv export — print a share string of your rules
/sv import <string> | import apply [merge|replace] | import cancel — check
    a share string, preview every rule, then apply it
/sv preset <name> [apply] — preview a preset rule pack; add apply to add
    it
/sv profile list|use <name>|copy <name>|delete <name>|rename <new
    name>|reset — settings and rules per profile; each character picks one

A key binding for toggle is listed under Key Bindings → AddOns → Skyveil.


LAYERS (BETA)
-------------
/sv layers opens the Layers tab. Sharing and hosting are off until you
turn them on.
Skyveil reads your layer in a zone from the ID of a creature you target
or mouse over.
Share joins SkyveilLayers, a visible chat channel. Each Share press posts one
line with your character, zone and layer. Anyone in that channel can
read it.
The list shows layers in your zone that sharers posted, how many hosts
are on each, and how old the post is. Older than 15 minutes is removed.
Click a layer to ask a host on it for an invite. One press every 10
minutes. If the hop reverts, that press retries with the next leave
order, up to 3 invites, each from a host with room under its cap.
Hosting: anyone can host while they can invite: solo, party leader with
under 5 in the party, or raid leader or assistant with under 40 in the
raid. A host's Skyveil invites the character who asked, up to 3 per
minute, never a blocked name. When the host cannot invite, Skyveil
refuses requests at once; the listing changes on the host's next Share
press or leaves the host count after 5 minutes.
You must be solo to ask. Your Skyveil accepts only the invite from the
host you asked, within 30 seconds.
After the hop, the group step runs and Skyveil reads your layer again.
It shows Hop held or Hop reverted. After a revert it tries the next
leave order at once: you leave, then the host leaves first, then the
host passes lead first. The order that holds is kept until /reload.
A solo host leaves the group; a grouped host stays in their group.
If the game blocks a part, Skyveil turns that part off and the Layers
tab names it.
/sv layerlog shows this session's layer events. It stays on your
computer and is cleared at logout, except the last 200 lines a saved
debug report copies (see DEBUG REPORT).
A join can move the host's whole group to your layer. Hosting in a group
puts your group's layer at stake.
Block a name with /sv layers block Name. /sv layers off stops sharing
and hosting at once. Skyveil does not ask, invite or auto-accept a
player your veil covers: a muted name, a veiled guild's member or a
remembered Skyborne.
Layer lists stay in memory for this session. Saved: your on/off choices
and blocked names as hashes.

Self-checks. The Layers tab and /sv layerlog show what each check
found this session:
T1: leave order 1 (you leave): your layer 10 s after leaving equals
    the target.
T1a: leave order 2 (host leaves first): the same reading.
T1b: leave order 3 (host passes lead, then leaves): the same reading;
    fails if the lead pass is blocked.
T1g: grouped host: your layer read after the asker joined equals your
    layer before.
T2: layer reading: creature IDs carry a layer field, and two different
    values were seen.
T3: hosting: the invite call ran from a request with no click.
T4: auto-accept: the accept call ran and you joined the host's group.
T5: auto-leave: the leave call ran and you were out of the group.
T6: sharing: a Share line was sent and your own line came back on
    SkyveilLayers.
T7: assistant hosting: as raid assistant, the invite call ran.


DEBUG REPORT
------------
/sv debug opens a report to copy (Ctrl+A, then Ctrl+C). It has the
addon version, client build, your settings, the last 200 layer log
lines, the hop and self-check results, whether you can host, and Lua
errors from Skyveil's own files, with times. Other players appear as
hashed IDs. It has no chat text and no guild roster. At most 64 KB;
the oldest log lines go first.
After the version and client lines comes one state line: state:
addon=<folder> ver=<version> errs=<count> T=<checks> R=<checks>. Each
check is its id and a code: P pass, F fail, U unchecked, - not run, H
held, V reverted, r read, s sent, c called, K kept, M moved. R is n/a
on Forever. The state line has no names, GUIDs or layer numbers.
Save and reload saves the report, including the last 200 layer log
lines, to the SavedVariables file
WTF\Account\<account>\SavedVariables\Skyveil.lua and reloads the UI.
A report is also saved there at each logout and /reload. The last 5
are kept. /sv debug sends nothing. Skyveil keeps a copy of errors from
its own files and passes every error on to the game's error handler.
SkyveilSync (in the download, optional) copies each saved report to a
"Skyveil Reports" folder on your computer. See SkyveilSync/README.txt.


HINTS
-----
The options panel ends in one muted hint line from your current state
and an Ask box. On Forever: nameplates off while the veil is on. On
the Layers tab: Share and Host off, or the next leave order after a
reverted hop. /sv ? <words> and /sv hint <words> search Skyveil's own
help on your client and print at most 2 lines, only when you type
them. The hint changes on game events and tab changes only. Hints send
nothing and never name players.


WHAT IT HIDES
-------------
Skyborne:
- Nameplate name text is blanked out of combat. The plate frame stays.
- Say, yell, emote, whisper, party, raid, guild, instance, channels
- System lines that name a remembered Skyborne
- Tooltips on mouseover
- Target / focus / compact raid names are blanked out of combat. The frame stays.
- Optional: Skyborne NPCs

Guild needle (none until you add one):
- Chat from a learned member, including say, yell, emote, whisper,
  general, trade, guild, party, raid, and instance
- A tooltip line, "Veiled guild". The plate stays.
- Guild invites, group invites, duels, and trades from a learned
  member, each only if that checkbox is on. They start off.
- Hand mutes and word filters, even if the guild checkbox is off

Learning a member happens when you target, mouseover, or see their
nameplate, or when a /who line contains <Guild>. A later look that
shows a guild which no longer matches clears the learned name.
A hand mute stays until you unmute.

/skyveil who sends one query. It does not scan on a timer.


WHAT IT CANNOT HIDE
-------------------
Addons cannot hide another player's 3D world model. The body still
renders. Engine-drawn floating names (nameplates turned OFF) cannot
be filtered per player. Turn nameplates on for the Skyborne veil.

While the veil is on, Skyveil checks chat bubbles once a second
and hides any whose text matches a say-scope hide rule (word
filters included), a name you mute, a learned name from a guild you veil, or (with the chat veil
on) a Skyborne name. Inside many instances the game does not give
addons the bubbles, so they show as normal there.

Race detection matches the strings Skyborne, Skyborn, and Shen'dorei.
Target one and run /skyveil inspect. A learned race id is kept so
detection does not depend on the localized name.

You are never veiled unless "Veil myself" is on. That includes a
guild mute of your own name.


DATES
-----
Launch is 4 Nov 2026, 3:00 p.m. Pacific, per Blizzard.

Forever groups by ruleset, not by realm. A large guild is not
avoided by changing server. The ignore list holds 50 names. This
filter is the local alternative.

Not affiliated with Blizzard Entertainment or any guild.


GUILD COMMAND: PRIVATE (off until /skyveil private on)
--------------------------------------------------------
Any guild can use it. The GM and officers build their own guild's
private pack in game (wings, ranks, reserves, quotas, rival and
sister lists, banks) and export it. The public addon ships only an
empty framework with no guild built in. Each guild's pack is kept
apart: a pack made for one guild will not import into another.

- A pack arrives in one of two ways. An import string
  (/skyveil private import) carries an HMAC checked with the guild key
  you paste with /skyveil private key. The key stays on your
  computer and is never synced or exported. Sync is not signed: a
  sync is accepted only when the addon message comes from the
  current guild master (full Name-Realm, from the guild roster) and
  the guild master wrote the seal, and the seal's integrity hash
  matches its data. Sync trust is a GM-sender check plus an integrity
  hash. Anything else is dropped, including seals passed on by
  officers.
- Member sections go over the GUILD addon channel. Officer sections
  go over OFFICER, or a whisper to one officer. They never go over
  GUILD. Every section is sealed, keeps its last 5 seals, and can be
  rolled back. The newest valid seal wins. A change to more than
  25% of a section since the last reviewed seal is held, even from
  the guild master. The current seal stays until an officer
  inspects, accepts or rejects it. Members never review held
  changes. Review is set only on your own client.
- Alliance Sync (off by default) links two guilds on the same or
  connected realms and the same faction. Both guild masters press
  Link, each sending a direct addon whisper to the other; the link
  forms only when each side has sent and received one. The addon
  cannot read another guild's roster, so it cannot prove who leads
  that guild. When the other character is visible to you (target,
  mouseover, party or raid), it must be the guild master of the guild
  it names, or the request is dropped. Each guild keeps up to 3
  pending requests, one per sender, and each expires a day after it
  arrived. A sender seen as that guild's guild master is marked
  Verified and is always admitted; it replaces every Not-verified
  request for that guild, and no Not-verified request is admitted
  while it is pending. When the list is full of Not-verified
  requests, a new one replaces the oldest. The accept prompt lists
  every pending sender's full Name-Realm and whether they are
  Verified. Pick one with /skyveil private ally accept <number>
  <guild>, or clear them all with /skyveil private ally decline
  <guild>. A request from a character you sent Link to links at
  once. After linking, only that pinned guild master (or a delegate
  they name) is accepted. Either guild master unlinks with one
  press, and each guild
  can then delete the other's data. Each guild picks which sections
  it shares. Officer-only sections, Standing and all bank data are
  never shared. A shared roster includes only members who turned
  on "Share with allied guilds" themselves (/skyveil private ally
  optin on). Every allied push is one press, by addon whisper to
  the other guild master or a delegate that guild master named.
  Allied data is stored apart from your own and is seen by your
  guild master and delegates, unless the guild master presses to
  share a section with the guild. A guild master change on either
  side suspends the link until both guild masters press Link again.
- Every send waits for you to press Send. Nothing here moves items
  or gold, kicks, demotes or penalizes anyone. Renaming a rank
  (GM press only) changes that rank's name in the guild settings. Strikes and fines are
  only logged, and an officer can send each member their own
  entries.
- Bank tools only track and flag. Snapshots are taken when you open
  the guild bank, or the bank on a character you mark as a bank alt.
  Classic Era, Hardcore and SoD have no guild bank, so only bank-alt
  snapshots work there.
- Rival guilds are tracked at guild level only. Player names and
  GUIDs are never stored.

Sync reaches only your guild's members, plus the allied guild master
and delegates for the sections you choose to share. Anything synced
to your client can be read by you or any tool on your machine. Keep sensitive data
officer-only. An officer's client holds everything it receives,
and that officer can share it.

Guild-level PvP rivalry is normal play. Organized harassment of a
guild's members (spam, griefing, following them out of PvP) breaks
Blizzard's harassment rules. This feature covers PvP-context calls
only.


GUILD MASTER CROSS
------------------
On by default. /skyveil cross off turns it off. It shows only on your
screen and sends nothing. The cross is the game's own guild tabard
emblem 97 from Interface\GuildFrame\GuildEmblemsLG_01, shown in red.

How it is decided: only by the game client. Your guild's guild master
is the roster member at rank index 0; the cross moves on the next
roster update when the guild master changes. Another guild's guild
master gets it only while the client can see that character (target,
mouseover, focus, party or raid) and reports them as their guild's
guild master. Names are matched as full Name-Realm. Addon messages and
anything a player says never decide it.

Where it appears: at the start of chat lines from that character
(say, yell, whisper, party, raid, guild, officer and channels), in
their unit tooltip as "Guild Master of <guild>", and next to Verified
senders in the alliance accept prompt. Not-verified senders never get
it. It does not appear on nameplates, unit frames or chat bubbles.


CHANGELOG
---------
2.3.0
Quiet hints: one hint line and an Ask box at the bottom of the options;
/sv ? <words> (or /sv hint) answers in at most 2 lines, only when you
ask. /sv debug reports carry a state line. SkyveilSync writes
SKYVEIL_LATEST.txt and SKYVEIL_LATEST_RETAIL.txt, a copy of the newest
report per client, and has a one-shot --local-llm-hint for a model on
your own computer. On retail, leave order 3 waits until the asker shows
as leader (5 s at most) and Layers shows the last shard seen, marked
stale. Nothing new is sent unless you run the one-shot hint.

2.2.0
Layers (Beta), off until you turn it on: read your layer, share it on
SkyveilLayers (a visible chat channel), ask a host for an invite, host
for others, hop checks and self-checks (see LAYERS (BETA)). /sv
layerlog. /sv debug report with Save and reload. An eleven-tab options
panel. The setup repeat line shows your repeat window. /sv repeats with
a value that is not a number says the range.

2.1.0
Chat rules with channel scopes, a blocked log with reveal and unblock,
presets, and share strings. Your word filters became rules in every
channel. Spam, repeat and low-level filters are off by default, so an
upgrade hides nothing new. Profiles per character. Alerts on your
own client (chat line, sound, raid-warning-style screen text, flash,
fade) for rules, roster, declines, rival sightings, seals, floods and
veiled-guild group joins. Blocked-line stats for 14 days. A guild
roster log with hashed names and rank numbers, plus a rank and activity
summary in memory. Guild needle notes and expiry. A Non-Latin preset.
Presets and imports are previewed before they apply. Minimap button and
Addon Compartment entry, three-step setup, a ten-tab options panel that
also opens as its own window (/sv config), and an enUS locale file.
Upgrades see What's new once. 2.1 sends nothing new.

2.0.0
Adds Guild Command: Private, off by default. See above. Sync trust is
a GM-sender check plus an integrity hash; sync is not signed.
Alliance Sync is off by default.
Adds the guild master cross, on by default. See above.
Uses the game's own look: Send prompts are the standard game dialog,
the copy box is the standard game window, and chat, tooltip and cross
colors come from the game's color set.
Request limits: an officer takes one request per member per minute,
at most 3 open tickets per member and 200 in the list (closed ones
are removed first). Wing requests must name one of your wings.
A full link request log refuses new senders; a logged request is
never pushed out. If the one you want was refused, link the real
guild master directly: /sv private ally link <Name-Realm> <guild>
Requests wait in your saved data. The save starts 5 seconds
after the first one arrives, so a logout or /reload keeps them.
The save is serialized and hashed over several frames instead of
all at once. All of Skyveil's sliced work and incoming addon
messages share one budget of 2 ms per frame and one queue: work
stops for the frame once the budget is used and the step that
crosses it ends. Each incoming addon message counts against the
budget from its first check and waits in the queue when the
budget is used.
Before a message joins the queue, its sender, the sender's rank for
that message type and the sender's rate are checked; a message that
fails is dropped. Protected senders are the guild master, pinned
allied guild masters, and each character this guild master sent a
Link to that is still pending (one per guild). Each allied guild's
delegates share one rate bucket of their own: all of that ally's
delegates together get 60 chunks per 10 seconds, the cap one member
gets alone, so one ally's delegates never use up another ally's
bucket; a name two allies both list counts on the bucket of the
guild whose name sorts first. Delegates wait in the members' lane; a guild master names at most 32 delegates,
and names past 32 in a received list are refused and counted in
/sv status. The rate cap is 60 chunks per 10 seconds per
sender; for a protected sender it is 460 chunks per 10 seconds,
which holds the largest message the addon accepts (400 chunks)
plus 60 more, so a guild master's largest seal is never refused for
its rate. The queue has 1000 places. 200 of them are kept for
protected senders. These incoming messages can be dropped:
- any message from anyone else while 800 messages wait;
- any message, even from a protected sender, while 1000 wait.
The queue has two lanes. Your own presses and saves and messages
from protected senders run first; messages from everyone else run
only when that lane is empty. Both lanes share the same 2 ms per
frame. A section seal is checked (hashed) inside that budget before
it applies, so it applies some frames after its last chunk arrives:
in the tests, a 30-ticket seal (27 chunks) applies about 240 frames
(about 4 seconds at 60 fps) after its last chunk, and a 200-ticket
seal (176 chunks) about 1600 frames (about 27 seconds) after it.
In the tests, a flood from members adds at most 4 frames to the
27-chunk seal's wait (measured +1 to +4 frames, depending on the
calibration run); the flood's messages wait or are dropped
instead.
Your own presses and saves are never dropped. /sv status shows how
many incoming messages were dropped this session and, when any
were, how many of them were link requests. A link request from another guild's guild
master is not protected until you link them, so a flood from
strangers can drop it; if /sv status shows dropped link requests,
link the guild master directly: /sv private ally link <Name-Realm> <guild>
A section seal received from the guild master is parsed, checked
and applied the same way.
An officer keeps at most 50 member requests (tickets and wing
requests) waiting to be saved. While 50 wait, a new member request
is dropped and the member is not told.
The link request log is kept on the guild master's client: one
entry per sender, up to 5000. Entries expire 24 hours after they
arrive, by your clock. When 5000 senders are logged, new senders
are not logged until older entries expire. Nothing is sent back
from it; linking is one press. The guild master empties it with /sv private requests clear.
Multi-chunk messages: at most 3 open per sender (a 4th replaces that
sender's oldest) and 100 in all (past 100, the oldest open message
from a sender other than the guild master and pinned allied guild
masters is dropped; if there is none, the new message is dropped).
The guild master and pinned allied guild masters are not held to 3,
a new message from them always gets a slot, and their open messages
are never dropped to make room. Chunks on a channel their message
type never uses are dropped.

1.1.4
Cleanup release. No new features. The license is now All Rights
Reserved (see LICENSE.txt).

1.1.3
The upgrade removes the old 1.1.0 default guild filter if one was saved.
Auto-declines are turned off only if that filter was set, or if all
four declines were already on. Otherwise they are left as they are.
Open the options panel and switch them back on if you still want them.
