Axsys Signals Product Manual
MVP edition
This manual is the words and the rules behind Axsys Signals. It is edition 0.6 (2026-09-28) and it describes product release 0.5.1. The user guide tells you what to click, screen by screen. This manual tells you what each word means, where each number comes from, and what the product does and does not do yet. Every number in section 5 is filled in from the code when this page is built, so the page and the product cannot drift apart.
The editions so far:
| Edition | Date | What changed |
|---|---|---|
| 0.1 | 2026-09-04 | First edition. |
| 0.2 | 2026-09-05 | Added the parts that shipped in the 9/05 build: your own sources with a CSV import and the industry starter sets, what produced results, a vote per lead with a reason, leads out to a CRM with the payload contract, the Health page with the reason codes, the switch that hides the ICP from members, the first login tour, the help button with Report a problem, and Ask for access. |
| 0.3 | 2026-09-06 | Brought in line with the 9/06 build. The tour is five steps, or three on a workspace with no accounts, all of them on Today, and it is started again from the Take the tour button at the top right of every page; the round question mark is retired and Help is a button beside it (sections 11.3 and 12.1). Health names each row after the collector rather than the channel, so no two rows repeat; it counts channels with results, clamps a window longer than the run history and says so, and has two new reason codes, not_collecting and not_client_facing (sections 3.1, 3.6 and Appendix B). Collector cadences say overnight where they run overnight. OSHA is not collecting and Financial profiles fills in numbers in the background, and both say so. "Signals caught this week" counts events by the day they happened, and the brief's revenue line is labelled Revenue (Appendix A). The two older pages outside the rail are staff only (section 2.15). |
| 0.4 | 2026-09-06 | The why block. New section 5.4 documents account.why: where _why_block gets its numbers, the shape of the object, that every figure is copied off the engine factor rather than worked out a second time, what a factor with no explanation does, and why the rows total the score exactly today. Section 5.6 and section 2.16 point at it, Appendix A.2 gains the queue row's Biggest gap line and Appendix A.3 is rewritten for the card the drawer and the brief now render. Section 8.2 says plainly that the payload's why is the engine labels line and not the block's sentence. Section 12.1 and section 13 are brought in line, and the drawer's facts line says revenue, not ownership. |
| 0.6 | 2026-09-28 | Release 0.5.1: a Good lead or Bad lead verdict takes one reason or several (sections 2.21 and 7.1, Appendix A). The comment is stored as "<reason>,<reason>: <why>", and a verdict whose reasons and why together pass the 280 characters the vote table holds is refused with the room left rather than cut. |
1.Overview
1.1What this build is
Axsys Signals is the product you sign in to at https://signals.srv1195619.hstgr.cloud. It gives your workspace a ranked list of companies that look ready to buy, with the evidence behind every score.
Here is the loop, in plain words. Overnight, our collectors read public sources: filings, news, court records, permits. A sync step turns what they found into observations, one dated sighting per signal per company. A rescore step updates each company's buying probability and lead time. Then the app builds your view: it picks the companies that fit your workspace, scores each one, and ranks them. You open the Today page, see who moved and why, and act on the hottest ones.
Two things about this build are true and need saying out loud. First, the sync and the rescore now run on a timer, at 06:30 UTC every morning, inside the app and with nobody starting them. They shipped in release 0.1.2. Section 3 explains what they do and how to tell whether last night's run landed. Second, the companies and signals you see come from the shared Axsys research lake. Your workspace picks a slice of it. It does not yet add to it.
1.2What this build is not
This manual is not the engineering design. The service design, the containers, the tables and the isolation rules live in signals-app/DESIGN.md in the code repository. It is not the user guide, which walks each screen. It is not a description of the internal Axsys CRM, which is a different product that shares one database with this one. And it is not the demo boards from earlier in the summer; those were static samples. This is the live product.
1.3Who this manual is for
- You, if you use the product and want to know what a number means before you act on it.
- Workspace admins deciding who to invite and what each role can do.
- The Axsys team reviewing the MVP against what was asked for.
- Anyone checking that what the screen says matches what the code does.
1.4Getting in
You sign in at https://signals.srv1195619.hstgr.cloud with your email and your Axsys password. There are two ways to get an account. A workspace admin, or Axsys staff for the first admin, sends you an invite email. Or you start your own workspace at https://signals.srv1195619.hstgr.cloud/signup, which takes a work email, refuses free mailboxes unless the address is on the allow list in SIGNUP.json, and creates nothing until the address is proved by the link we email you. Someone with no invitation can ask for one at https://signals.srv1195619.hstgr.cloud/request: name, work email, company, and one line on what they sell. That form holds no session and creates nothing. It writes one audit row (action access.request, no workspace, no user, detail name, email, company, sells and free_email), emails the Axsys team "Access request: <company>" with the four fields and the caller address, and answers "Thanks. We will write back within two working days." The throttles are the shape the forgot password form uses: three an hour per network address (bucket request-ip) and three a day per email (bucket request-email), checked after the fields are validated so a typo does not burn a slot. A free email domain is accepted and flagged in the email to the Axsys team. The "Ask for access" and "Talk to sales" buttons on the marketing pages point at this form. The link in an invite works for 14 days. If you already have an Axsys password from the CRM, you accept the invite with that same password. If you are new, you pick a name and a password of at least 10 characters.
If your CRM account only ever used Microsoft sign in, you have no Axsys password yet. The invite page then says "This email has no password yet" and points you at Reset password. Set a password by email first, then open the invite link again.
If you forget your password, use the Forgot link on the sign in page. A reset link is emailed to you and works for one hour. You can ask for one up to three times an hour. One password serves both this product and the Axsys CRM, so a reset here also changes your CRM password if you have one. A reset also signs out every other session you had open. This is on purpose, not a mistake: there is one users table.
Ten tries on one email inside an hour, right or wrong, lock that email for up to an hour. Ten tries from one network address in fifteen minutes lock that address for fifteen minutes. The screen says "Too many attempts. Wait up to an hour and try again, or reset your password, which clears the wait." A password reset clears both locks.
You stay signed in for 30 days of use, and 90 days at most from the day you signed in. Then you sign in again. If the product itself is having trouble, the public status page at https://signals.srv1195619.hstgr.cloud/status says so and needs no sign in.
Two more words you will see everywhere. A workspace is your company's private space: its members, its ICP, its votes. An account is one company in your ranked list.
2.The words we use
One plain sentence first, then the rule behind it. Where a word means something different in another part of the system, we say so.
2.1Source
A source is a place we read on a schedule to catch events: SEC filings, a news feed, a court record, a permit register.
The rule: every observation remembers the channel that found it, and the app shows it as "SEC EDGAR", "Google News", "Finnhub" and so on. Two other things are called sources and are not this. The Library holds source cards (kinds: filing, news, job postings, web, registry, api) written by Tommy's method. They describe where a signal could be watched, and most are not read by any collector yet. And the block on the Signal desk called "Source library" is really a list of signal types, not places we read. That block is on the list to rename (section 13).
2.2Collector
A collector is a program that reads one or more sources on a timer and writes down what it finds.
The rule: seven collector channels run today (section 3.1). They run for everyone at once and do not know which workspace you are in. They write raw findings. The sync step turns those into observations. Whether a collector ran, and how its run ended, is read from the automation server and shown on the Health page (section 3.6). When a feed inside a collector breaks, the collector still records nothing about that one feed, so a dead feed inside a live channel looks quiet rather than broken until feed level tracking lands.
2.3Signal
A signal is a kind of event that tends to happen before a company buys: a new CFO, a going concern warning, a wave of job postings.
The rule: the running catalog holds one entry per signal with a name, a weight for how much it usually matters, the evidence area it belongs to, and a detection mode (convergence or circumstance). The Library shows a second, richer view of a signal: its chain (what triggers it, why it matters, what usually happens next), a chain grade, an evidence tier, and the sources where we would watch for it. The catalog scores. The Library explains.
2.4Observation
An observation is one dated sighting of one signal at one company, with the words we found and where we found them.
The rule: an observation carries the company, the signal, the date it was seen, the evidence text, an evidence link, the channel, and an active flag. Only active observations count. All of an account's active observations feed its score and confidence. The brief shows the 8 newest. Section 3.3 says how an observation is born. The evidence text is the document title, then " | " and the first 280 characters of the excerpt when the raw finding has one; the app shows the part after the bar as the excerpt. The evidence link is the raw finding's source address, carried on new rows since 2026-09-05. A bounded nightly pass also fills it in on older rows that have none, in batches of 200 and at most 2,000 a night, so "no link on file" on old results clears over a few nights. The desk, the drawer and the brief show "Source" as a link when there is one and "no link on file" when there is not.
2.5Evidence area
An evidence area is where a signal's proof comes from: filings, news, hiring, the courts, and so on. Proof counts more when it comes from different areas.
The rule: each catalog signal belongs to one evidence area. Fit counts how many different areas your account's observations cover; three or more scores the most (section 5). The Library's independence domains are the same idea at the method level: repeating within one area is discounted, agreement across areas counts. On the brief the area appears as the "family" of each result.
2.6Universe
The universe is the set of companies the app can show you at all.
The rule: a company is in your universe when it is actively monitored, not marked do not contact, has a known headcount, has a buying probability above zero for your volume, and has at least one active observation that counts for your workspace. Section 4 has the full rules, the top 40 cut, and the ICP filters that apply once a document is approved. The universe is the Axsys research lake, shared by every workspace. Your workspace settings pick your slice of it.
2.7Volume
A volume is the product line you sell, and it picks which probability the app reads.
The rule: three volumes exist, AGENTS, STRAT and RESC. The nightly scorer gives each company one buying probability per volume. Axsys staff set your workspace to one volume when they create it. Only observations in your volume count for your accounts. If no volume is set, the app uses the highest of the three probabilities and all observations.
2.8Fit
Fit says how well a company matches who you sell to and how much we know about it. It goes up to 15 points.
The rule: three parts. Size band, up to 25. Evidence breadth, up to 20. Profile completeness, up to 15. Section 5.1 has the table. Fit changes slowly, because headcount and profile do not change often.
2.9Timing
Timing says how soon we think a buying window opens. It goes up to 25 points.
The rule: when the scorer has a lead time estimate in months, timing comes from that, and one month scores the most. When it has none, timing is scaled from the probability and capped at 24. The window label (Next 30 days, Next 90 days, Next 120 days, Beyond 120 days) comes from the same months. Section 5.1 has the table.
2.10Score
Score is Fit plus Evidence plus Timing, out of 85 when the profile sets a size band and 100 when it does not. Nothing else is added.
The rule: the small +8 to +2 beside each result are the weight of that signal type and are not summed into the score (section 2.16). No boost or penalty is applied today: the targeting rules on the ICP page are shown, not applied (section 6.1). Score decides the order of your queue.
2.11Tier
Tier puts a score into one of four buckets.
The rule: Tier 1 is 80 to 100, Tier 2 is 65 to 79, Tier 3 is 50 to 64, Tier 4 is under 50. The cut points are 80, 65 and 50. Other things in the wider system are also called tier and are not this: the CRM's TIER_1 and TIER_2 label (which counts signal volume), the catalog's T1 to T3 (which is signal value), and the Library's discoverability and evidence tiers. In this product, "Tier" always means the score tier, with one marked exception: the tier chip on a row of the Your signals page is the catalog's T1 to T3 for that kind of signal, its value, not a score (section 6.5).
2.12Status
Status is the advice that goes with the tier.
The rule: Tier 1 reads Pursue now, Tier 2 reads Develop, Tier 3 reads Monitor, Tier 4 reads Low priority. It tells you what to do, not how the score was built. Today it comes from the tier and nothing else.
2.13Surging, Heating and Monitoring
Surging, Heating and Monitoring are the same scale as the tiers, with different names.
The rule: Surging means a score of 80 or more, which is Tier 1. Heating means 65 up to one below 80, which is Tier 2. Monitoring means below 65, which is Tiers 3 and 4 together. So one scale carries three names today: the tier number, the status word, and this glyph word. Note the overlap: the status word Monitor covers Tier 3 only, while the glyph word Monitoring covers Tiers 3 and 4. This is a naming overlap, not two different measurements. Jeff is picking one vocabulary. Until he does, this manual says plainly that they all measure the same thing.
2.14Confidence
Confidence says how solid the evidence for an account is: Strongly Supported or Inferred.
The rule: an account reads Strongly Supported when at least one of its observations belongs to a signal whose catalog detection mode is convergence. Otherwise it reads Inferred. The mode comes from the catalog entry for the signal type, not from the evidence we actually read. So today the label describes the kind of signal, not the strength of that particular sighting. A third label, Verified, appears in the model table and is never assigned by the code. Both are on the list (section 13).
2.15Provisional
Provisional means we have exactly one observation on the account and no lead time estimate. Check before you act.
The rule: the flag is computed for every account and carried in the data. The Today page's "Thin evidence" filter is a close cousin: it shows accounts with one shown result or none. It is not the same test. The word Provisional shows only on the two older pages kept outside the left rail, https://signals.srv1195619.hstgr.cloud/app/board and https://signals.srv1195619.hstgr.cloud/app/desk-legacy. Those two pages are staff only from this release: a member of a workspace, whatever their role, is refused. The flag itself still rides in the data. The Today drawer and the brief do not show it.
2.16Points
Points are the small +8, +6, +4 or +2 beside each result. They show the weight of that signal type in the catalog.
The rule: +8 for the heaviest signal types, down to +2 for the lightest. Points are display only. They are never added into the score. What does reach the score, since release 0.4.0, is the catalog rating of the account's strongest signal (section 5.1, the strength term): a T1 signal on the account earns more than a T2, once, however many results there are. That is a different number from the points and it is the only way a single signal type moves an account. The "Signals caught this week" tile counts results, not points. The other numbers on the brief, the ones inside the Why this score card, are the opposite: those rows are the score itself and they add up to it (section 5.4). Two sets of numbers on one screen is the one thing readers of that page get wrong, so both the card and the guide say which is which.
2.17Lead time and shelf life
Lead time is how long before a buying window a signal usually shows up. Shelf life is how long the signal stays useful after it shows.
The rule: two different lead times exist. The Library's chain rows carry a lead time and a shelf life per signal, in days or in bands, from Tommy's method. Not every signal has values loaded yet, and they are not used in scoring. Scoring uses the company's lead time estimate in months from the nightly scorer, which feeds Timing. The sync gives every observation a shelf life of 180 days for the scorer. The app view does not apply that expiry. It shows any observation still marked active, so a very old sighting can still appear. A rule of thumb: a last signal older than 90 days means the picture may be stale.
2.18Grade
A grade is the Library's mark out of 10 for a category, a signal or a source, in one industry.
The rule: grades are per industry. A 7.1 in one industry is not a 7.1 in another. The Library shows grades for the first industry in your approved ICP, falling back to the industry Axsys set on your workspace when the ICP names none, and says "Set your workspace industry to see grades" when neither has one. Today's grades come from a synthetic backtest, not from your results. The basis is printed on each card.
2.19ICP
Your ICP is one statement of who you sell to, plus the filters the queue uses.
The rule: the workspace keeps a volume, an optional SMB cap on headcount and a display name, written by Axsys staff when the workspace is created, plus one ICP document. An admin writes that document on the setup flow (one question, then six), or pastes one, and approves it; the Axsys team can also load one. Once approved, its industries, size band, locations and exclusions are real filters on the queue. The ICP page shows it, and admins change it with the Edit button. Section 6.
2.20Calibration
Calibration is the step where you and the desk compare answers and agree the final list of signals to watch and the line each must cross to count.
The rule: calibration is not part of the first version. The Workshop screen where it happens is optional and off the main path, reachable but not required. Per signal thresholds with an audit trail and a re run button come later, once the good lead definition with bounds arrives from Tommy and Jeff.
2.21Good lead and Bad lead
Good lead and Bad lead are your verdict on a lead, and a lead is one company in your queue.
The rule: one verdict per person, per company, per workspace, with one or more reason codes from a list of nine and a why of up to 240 characters (the picker offers four of them under Good lead and six under Bad lead, and any number of them may be picked together, section 7.1). It is kept in the same vote table as the 1 to 5 stamps, under a key that names the company (section 7.1). Nothing in the scoring reads it. The Axsys team reads the votes by hand each week. Admins and contributors vote; viewers see the tally. Section 7.
2.22Fired
A collector fired when it ran, it found something, and what it found matched one of your companies. All three, or it did not fire.
The rule: Health (section 3.6) takes the run from the automation server and the match from your workspace's own results. "It ran" is a run, not a fire. "It found things about other companies" is not a fire for you. The whole dictionary of what a run can say is Appendix B.
3.Where signals come from
3.1The collectors we run today
Three numbers get counted here and they are all correct, so say what each one counts before reading the table.
- Nine channels. The source registry has nine rows, and the Sources page shows one row each (section 6.6). A channel is a group of feeds we read the same way, and the channel is what a finding remembers.
- Six of them are collecting today. The other three say so themselves, on the Sources page and on Health. OSHA inspections has never collected: the address it was pointed at does not exist, so nothing from it has ever reached a workspace. SBA loan records and Financial profiles are loaded in batches when we load them, not on a clock, and Financial profiles is mostly there to fill in the numbers on an account, so very few of its rows become results in a queue. All three keep their switch, so a workspace can stop counting what is already there.
- Fourteen collectors. A collector is one workflow on our automation server, or a script, or a batch load. The Health page shows one row each, fourteen rows, and each row is titled with that collector's own plain name, never with our internal name for it, so no two rows read the same. Several collectors still write into one channel: six feed Google News and trade press and six feed SEC filings, with overlap between the two lists, and the Channel line on each row says which (section 3.6).
So Sources counts places we read, Health counts the things that do the reading, and the table below counts the ones still reading. Counted from the registry in the code on 2026-09-06.
The list is at channel grain, which is the grain we record: each finding remembers its channel, not the exact feed inside the channel.
| Channel | What it reads | What it tends to catch |
|---|---|---|
| SEC EDGAR | Full text search of SEC filings | Material weakness, restatements, late filings, going concern language, guidance cuts, restructuring, divestitures |
| Google News and trade press | 29 saved news searches, five trade sites we read directly (Construction Dive, Facility Dude, HR Dive, Industry Week, Retail Dive) and two press wires (NASDAQ press releases, PR Newswire): 36 feeds in all | AI initiatives announced, layoffs and reorganisations, acquisitions and mergers, troubled projects, outages, recalls |
| Finnhub | A company news API, by ticker | The same kinds of news for listed companies |
| OSHA | Workplace inspection records | Nothing yet: this one is not collecting |
| CourtListener | Court records | Lawsuits and disputes |
| Tavily re research | A weekly web search on the biggest companies that have not moved (40 companies, Mondays) | Fresh news on stuck accounts |
| Austin permits | The City of Austin building permit register | Facility expansion |
That is seven rows, and one of them, OSHA, is collecting nothing. The last two make the nine: SBA loan records and Financial profiles are loaded in batches. Older observations carry the labels "SBA loan data" or "FMP financial ratios" from earlier collectors, and six newer peer comparison rows now belong to Financial profiles as well, so that channel can be counted and switched off like any other. All of them are still in the lake, so the Sources page lists both channels with a switch (section 6.6).
What this grain means for you: on the Sources page an admin can switch off a whole channel, like Google News, for your workspace (section 6.6). Switching off one newspaper inside it is a per feed promise we cannot keep until collectors record which feed each finding came from. This is on purpose, not a mistake. It is the honest state of the data.
3.2What "fired" means
A collector fired when three things happened: it ran, it found something, and what it found matched at least one of your companies. All three, or it did not fire. A collector that ran and found nothing for you is not broken, it is quiet. A collector that did not run is the one to ask about. Health (section 3.6) shows the run from the automation server and the match from your results, so those two are no longer told apart by guessing.
One thing the app still cannot tell apart: "the sources had nothing" and "the sources had things, none about you". Until feed level tracking, both read as found nothing for your companies. The words are the dictionary in Appendix B, to be confirmed at the 9/10 standup.
3.3How an observation is born: the sync
The sync is the first half of the nightly run described in section 3.5. Here is exactly what it does, in order.
- It reads the catalog to learn each signal's detection mode.
- It reads every raw finding the collectors wrote, in pages, so nothing is missed.
- It skips a finding with no company attached.
- It maps the finding's subcategory to one or more catalog signals. One real event can become up to three observations, one per volume, because the same event means different things to different product lines.
- Some subcategories are deliberately not mapped and never become observations: generic growth equity, private placements, IPO filings, record revenue, fastest growing lists, guidance raises, plain earnings misses, discrimination or harassment, union disputes, customer lawsuits, an AI leader hired, an AI vendor selected, an AI evaluation under way. These are ordinary business events that do not by themselves say a company wants what we sell. Not a gap in collection. A choice.
- Acquisition headlines get a closer look. A private equity pattern (a named sponsor, "platform acquisition", "private equity acquires") maps to the sponsor backed acquisition signals. The word "merger" maps to the merger signals. Anything else maps to a plain acquisition signal.
- Each observation gets the company, the signal, the volume, the detection mode from the catalog, the date the finding was created, a shelf life of 180 days for the scorer, the channel and subcategory as its source, and the document title as its evidence text.
- The script deletes its own earlier rows and writes the new set, so running it twice never doubles anything.
3.4The rescore
After the sync, in the same nightly run, the scorer recomputes each company's buying probability for each volume and its lead time estimate in months. It reads observations inside their 180 day shelf life. Every cached view is then thrown away, so the first page anyone opens that morning is built on the new numbers.
3.5The nightly run
Both steps run every morning at 06:30 UTC, on their own, inside the app. Nobody starts them. They shipped in release 0.1.2 and they are what makes the Today page's line "scored this morning" true.
- What it does, in order. One run at a time, under a lock, so two can never overlap. The sync of section 3.3, then the rescore of section 3.4, then every cached view is forgotten so the morning queue is built fresh.
- It adds, it never empties. The carry is incremental. A run that would remove more than a fifth of the rows already on the desk refuses the removal and says so in the log, because a broken collector must not be able to wipe your evidence.
- How to tell it ran. The Signal desk header reads "Evidence carried <date and time> UTC". The public status page at https://signals.srv1195619.hstgr.cloud/status carries the same line. A failed night keeps the last good stamp rather than naming a night that did not land, so the stamp never flatters.
- Where it runs. Production only. Staging shares one database with production, so it is deliberately left unarmed; if both ran, the carry would happen twice. Staff can also start a run by hand and read the last run's numbers.
- What still needs a person. The collectors themselves are workflows on the automation server, on their own clocks (section 3.1). The nightly run carries in what they found; it does not fix a collector that broke. The Health page (section 3.6) is where you see that.
3.6Signal health
The Health page (https://signals.srv1195619.hstgr.cloud/app/health, open to any member) says, per collector, whether it ran, whether what it found landed for one of your companies, and why not when it did not, in one plain sentence per row, over a window of 1, 7 or 30 days. Here is where each part comes from.
- The runs. The app reads the automation server's own API: the list of workflows, then the executions of every workflow named as a collector in the source registry (section 6.6), inside the window, paged with a cursor. The server address and its key are two settings on the box, N8N_API_URL and N8N_API_KEY. They are read at request time, used for reading only, and never sent to a page or written to a log. Without them the page says "Health needs the n8n key on the server." and nothing else breaks. The answer is cached for five minutes per window and shared by every workspace, so the automation server is asked at most once per window per five minutes. The crawl also has 20 seconds of clock for the whole page. When that runs out, the rows it did not reach come back marked not checked, with the sentence "We ran out of time before we got to this one. Reload in a moment.", and the whole answer is marked partial. A partial answer is kept for 30 seconds instead of five minutes, so the next reload fills the gaps.
- The window, and the history behind it. The chips ask for 1, 7 or 30 days. The automation server keeps about a fortnight of run history, so a 30 day question cannot be answered honestly from it. The crawl learns the oldest run it can still see as it pages, and when the window asked for reaches further back than the history does, every count and every sentence is written against the shorter real window and the page prints the reason: "The run history only goes back 14 days, so this window shows the last 14 days, not 30 days." The chip the reader pressed stays lit. The alternative, dropping the 30 day chip, would have hidden the fact that we hold only a fortnight.
- The code. Each execution carries a status. The map from a status to a code, and the words in an error text that turn a plain failure into a more exact code, are in Appendix B, which says the same thing as the file
docs/signals/reason-codes-2026-09-05.mdin the product repository and as the dictionary in the code. The row shows the newest finished run's code. A run that is still going does not decide the row; the sentence mentions it. - The row's title. A row is titled with the collector's own client safe name: News sweep, Hiring and workforce sweep, Austin permits pull, and so on. Our workflow name and its id are not in the answer at all; they are used on the server to do the reading and then dropped. Every collector has a name of its own, so no two rows carry the same title. The Channel line under the sentence names the channels that collector feeds, in the same words the Sources page uses, and that is the only place a channel name appears on a row.
- The match. A row that ran is joined to your workspace's results by channel, using the per channel counts for the last 7 and 60 days (section 6.8). Results are recorded per channel and not per collector, so a row only claims a find from a channel it is the sole writer of. A channel with a result inside the window makes the row ran_found, "found results for you on <date>". None makes it ran_no_match, "found nothing for your companies". A collector that shares every one of its channels with another collector says so instead, and its results are counted on the channel. This is the only part of Health that is per workspace; everything else is the same for everyone.
- The tiles. Collectors (the number of collector rows on the page, 14 today, one per name in the registry, not the nine channels the Sources page counts), ran (at least one good run in the window), channels with results (how many of the nine channels landed a result for your companies inside the window, or "not known yet" when your results could not be read), failed (at least one failed run). The third tile counts channels rather than rows because results are recorded per channel.
- The grain. One row per collector, titled with the collector's own name. The foot of the page says "Rows are per collector until feed level tracking lands; then per feed." The codes ran_empty, url_changed and expired_card are in the dictionary for that day, and nothing produces them yet. Five codes are about the row and not about a run: not_automated for one we load by hand or by a script (two rows today), not_client_facing for one that fills in the numbers on your accounts in the background (one row today), not_collecting for one that is not collecting at all (one row today), not_found for a collector the automation server does not list, and not_checked for a row the 20 second budget did not reach. Each of the five describes its own row and never the whole channel, because two collectors on one channel can be in two different states. All five are quiet states with a plain grey chip, and all five are in Appendix B.
The Signal desk's status column, which used to read "Live in sample" on every row, now reads "Last result <date>" from the newest observation of that signal type in your workspace, or "No results yet". The page paints it green only when the date is inside seven days. That column is a fact about your results; whether the collector ran is Health's job.
4.How a company gets into your view
4.1The universe rules
A company must pass all five tests to be in your universe.
- It is actively monitored. Archived rows and rows flagged as junk are out.
- It is not marked do not contact.
- Its headcount is known and above zero.
- Its buying probability for your volume is above zero.
- It has at least one active observation in your volume.
One workspace setting narrows this further. If your workspace has the SMB flag, only observations of signals meant for SMB or for both segments count, and companies above your headcount cap are out. The cap defaults to 500 employees when no number is set. When the workspace has an approved ICP document, four more filters apply on top: industries, size band, locations and exclusions (section 6.2). A workspace with no approved document runs on the five tests and the SMB setting alone. One more rule sits in front of all of these: a kind of signal switched off on the Your signals page is removed from the observation set before the tests run, so it cannot satisfy test 5 and it counts nowhere (section 6.5).
4.2The top 40
Every company that passes is sorted by its probability for your volume, highest first. Ties are broken by how many observations it has, then by how recent its newest observation is. The first 40 become your accounts. The Today page then sorts those by score. So probability decides who gets in, and score decides the order you see. The universe note in the data says how many companies qualified and how many are shown. The "Why this many" box on the ICP page and under the Today tiles puts those counts on the screen (section 6.2).
4.38 results per account
Each account shows its 8 newest active observations. Older ones still count for fit, breadth and confidence. They are just not listed. The number of older observations not shown is stated in the universe note.
4.4The 60 minute refresh
Your view is built the first time someone in your workspace opens a page, then kept for 60 minutes. After that, the next page load returns the copy you have and rebuilds a fresh one in the background, so a page never waits on the database. If the database is slow or down, you keep seeing the last good copy and a "Live data delayed" band appears. A copy is also saved to disk on the server, so a restart during an outage still has something to show. Nothing you do, including a vote, triggers a rebuild.
Until 2026-09-05 the built copy was trusted for ten minutes. It is trusted for an hour now. The reason it can be: every change that should move the queue throws the copy away by name at the moment it happens (an ICP approve, a signal switch, a source switch), and the nightly carry brings in the new results, so the clock is not what keeps the view honest. The shared catalogs are kept an hour too, and a workspace's off switches for a minute.
Dates on the Today page count from today in UTC. "This week" means the seven days before that date.
5.How the score is built
5.1The arithmetic
Every number below is injected from the code when this page is built. The score has three groups and eight or nine terms, depending on one thing: whether your profile sets a size band. If it does, every company in your view is already inside that band, so size is not scored, because a term that is the same for everyone cannot tell anyone apart. Your score is then out of 85. A workspace with no band keeps the size term and scores out of 100. The card says which in words.
| Group | Term | What we look at | Points |
|---|---|---|---|
| Fit | Size band fit | Only when the profile sets no band. Headcount inside 100 to 2,000 scores 15, within reach of it 9, further out 4, no headcount 0. | up to 15, or not scored |
| Fit | Profile completeness | Industry on file adds 8. Website domain verified adds 7. | up to 15 |
| Evidence | Breadth | Observations in three or more evidence areas score 20. Two areas 14. One area 8. | up to 20 |
| Evidence | Corroboration | Evidence from three or more different sources scores 10. Two sources 6. One source 0. | up to 10 |
| Evidence | Strength | The catalog rating of the strongest signal on the account. A T1 signal scores 10, a T2 6, a T3 3. Where our signal is paired with one in the signal library that is rated Forcing (an event that forces a decision), strength is 10 whatever the catalog tier says. | up to 10 |
| Evidence | Weight | Four or more pieces of evidence score 5, three 4, two 3, one 2. More pieces add less each time. | up to 5 |
| Timing | Lead time | From the soonest signal on the account, by its lead time band. Where our signal is paired with one in the signal library, the library's band is used; otherwise the catalog's. The bands: inside 90 days 15, 90 to 120 days 12, 120 to 180 days 9, beyond 180 days 5, varies by circumstance 7. Only when no signal carries a band does the company's own lead time estimate stand in, on the same scale, and only when there is neither does a probability path apply, capped at 7. | up to 15 |
| Timing | Freshness | The newest piece of evidence inside 30 days scores 10, inside 90 days 7, inside 180 days 4, older 1. | up to 10 |
| Fit total | up to 15 with a band, 30 without | ||
| Evidence total | up to 45 | ||
| Timing total | up to 25 | ||
| Score | Fit plus Evidence plus Timing | up to 85 with a band, 100 without |
Why it is built this way. The previous score had four terms, and measured on a real board two of them did nothing: size scored full marks for every account, and timing, which decided two thirds of the order, came from a company column that was empty for 86% of companies. None of the signals in the library could move the number. This model scores what actually varies between the companies in your view, and a signal's own rating and lead time now reach the score. The full analysis is in the repository as docs/signals-scoring-parameters-2026-09-09.md.
The window label comes from the same lead time term.
| Soonest signal fires | Window shown |
|---|---|
| Inside 90 days | Next 90 days |
| 90 to 120 days | Next 120 days |
| Later, or varies | Beyond 120 days |
| Beyond 180 days | Beyond 180 days |
The tiers are shares of the maximum, so a workspace scored out of 85 and one scored out of 100 sit in the same bands. Pursue now starts at 80% of the maximum, Develop at 65%, Monitor at 50%.
| Tier | Score, out of 85 | Score, out of 100 | Status | Glyph word |
|---|---|---|---|---|
| Tier 1 | 68 to 85 | 80 to 100 | Pursue now | Surging |
| Tier 2 | 55 to 67 | 65 to 79 | Develop | Heating |
| Tier 3 | 42 to 54 | 50 to 64 | Monitor | Monitoring |
| Tier 4 | under 42 | under 50 | Low priority | Monitoring |
The data also carries "points to next tier" for every account below Tier 1: the next cut point on that workspace's scale minus the score.
5.2Worked example one: a Tier 1 account
Take a software company with 800 employees in a workspace whose profile sets a band of 100 to 2,499, so size is not scored and the score is out of 85. Its industry is on file and its website is verified. It has four observations in three different evidence areas, read from three different sources: a filing, a news story and a court record. Its strongest signal is a T1. The soonest of its signals is one that usually fires 60 to 90 days before the spend, and the newest piece landed twelve days ago.
Profile: 8 plus 7, so 15. Breadth: three areas, so 20. Corroboration: three sources, so 10. Strength: a T1, so 10. Weight: four pieces, so 5. Lead time: inside 90 days, so 15. Freshness: inside 30 days, so 10. Score is 15 plus 45 plus 25, which is 85, the most a banded workspace can score. That is 68 or more, so Tier 1, Pursue now, Surging, with the window Next 90 days.
5.3Worked example two: a Tier 2 account, and what moves it
Same company, same profile, same three sources, same T1 signal, same twelve day old evidence. The only change: all four observations come from one evidence area, say four news stories.
Profile 15. Breadth: one area, so 8. Corroboration 10. Strength 10. Weight 5. Lead time 15. Freshness 10. Score is 73 of 85. That is 55 or more but below 68, so Tier 2, Develop, Heating. The card says the most room is in the spread of evidence, where 12 of the 20 points are still open.
One more evidence area is worth six of those points: two areas score 14 instead of 8, and the score becomes 79, which is Tier 1. This is still the lesson of the score. Four stories from one place do not add up. One filing plus one story do. Breadth needs different areas, not more stories from the same area. And this build adds a second lesson: a strong signal, confirmed in more than one source, that fires soon and landed recently, counts for more than a weak one seen once a long time ago, even when both sit in the same area.
5.4The why block
The engine works out the parts of a score. _why_block in signals-app/signals_dataset.py turns those same parts into words and hangs them on the account as account.why. The account brief and the Today drawer render the whole card; the Today queue row prints one line of it.
Where the numbers come from. signals_scoring.score_account builds every term with its own label, its note and its short words, and _build hands the result to _why_block. The block adds nothing: it sorts, sums, and writes the sentence.
Copied, not recomputed. Each row takes earned from its term's v and available from its m, and gap is available minus earned, floored at zero. The one figure the block works out for itself is the points to the band above: the next cut point on this workspace's scale minus the score.
The shape. account.why is an object with these keys.
| Key | What it holds |
|---|---|
headline | One sentence: the account name, the score out of its maximum, the band that score puts it in, then the parts at full marks, then each loss as points against the part in client words. |
factors | One row per term, in order: the fit rows, the evidence rows, then the timing rows. Each row carries label, engine (the engine's own label), noun, earned, available, gap, note, short, group (Fit, Evidence or Timing) and key. |
gapTotal | The sum of every gap. |
short | The short of the biggest gap, or null. This is what a Today row prints after "Biggest gap:". |
lift | Null in the top band. Otherwise points, tier, tierLabel, factor, room, of, and text, the finished sentence the card prints. |
sizeNote | The sentence saying size is not scored on this board, or null when it is. |
max and cuts | The scale the score is out of, and the cut points on it. |
Gaps are sorted biggest first with the label as the tie break, so two accounts with the same numbers name the same part and the order cannot wander between builds.
A factor we cannot explain says so. The block never guesses. The lead time row says which path it is on: a signal's own band, the company's estimate, or the probability path that never passes 7 of 15. If the whole block is missing, which happens when a page is served from a copy of the dataset made before this build, the two pages rebuild the rows from the raw fitFactors, evidenceFactors and timingFactors and print "We do not have a plain summary for this account yet." where the sentence would be. No number is ever made up.
The rows total the score, exactly. Every account carries negative, which is 0: nothing takes points away in this build. So the rows add to the score printed on the double rule at the foot of the card, always, and the card can say "Score, N of 85" without a caveat.
What each screen takes. The brief and the drawer render the whole card, in the same order: the sentence, the size note when there is one, the Fit group with its subtotal, the Evidence group with its subtotal, the Timing group with its subtotal, the score on a double rule, and lift.text when there is one. The Today queue row takes short only.
5.5Adjusting the score
A workspace may carry its own multipliers for the terms, between 0 and 2, in dataset_config.scoring. A multiplier scales both what a term earns and its ceiling, so the card still adds up and the maximum moves with it. Only four terms are meant to be offered to a client, chosen because on a real board they explained four fifths of the ranking between them: Evidence breadth (distinct evidence areas), Corroboration (distinct source channels), Freshness of the newest evidence, Strength of the strongest signal (catalog rating). The other terms sit behind their defaults. There is no screen for this yet; the mechanism is in place so that the screen is a form, not a scoring change.
5.6Confidence, provisional and points on the brief
Beside the score, three things travel with an account and are not part of the score. Confidence (section 2.14) is on the brief and tells you whether any of the account's signals is a convergence type. Provisional (section 2.15) flags one observation and no estimate; it is in the data and shows only on the two out of nav pages. Points (section 2.16) sit beside each result and show that signal type's weight. None of them moves the score; the strength term reads the catalog rating of the strongest signal, which is a different number from the points.
5.7Questions people ask
"Why is there only one Tier 1 account, and only about 48 companies in my list?"
Because Tier 1 needs 80% of the maximum, and that takes evidence in three different areas, confirmed in more than one source, with a strong signal that fires soon and landed recently. Few companies have all of that yet. The list is small because the universe is the companies the lake already knows and has evidence for. Adding companies to the lake is a separate step. It is not the signals failing, and not the ICP being too narrow on its own.
"The score is 67. Is that really different from 68?"
By one point, and by a tier boundary. The cut points are fixed shares of the maximum, not judgments. The Why this score card on the brief names the part that is short, how many points it is short by, and how many points would carry the account into the band above, so nobody has to work it out from the totals (section 5.4).
"Why is my score out of 85 and not 100?"
Because your profile sets a size band, so every company in your view is already inside it, and scoring size would give everyone the same points. We do not score a term that cannot tell companies apart. A workspace with no band scores out of 100, and the tiers are the same shares of the maximum either way.
6.Your ICP and how it changes the view
6.1The ICP document
Each workspace holds one ICP document. It is stored on the workspace record, in the same settings block the app already reads on every request, so no database change was needed to ship it. When the workspace table gets its own ICP column, only the two read and write helpers in the app move; nothing else changes.
The document carries:
- version: a whole number that goes up by one each time an admin approves.
- source: "pasted" (the Yes path), "answered" (the six questions) or "seeded" (loaded by the Axsys team).
- status: "draft" while the admin is working, "approved" once they press Approve. Only an approved document changes the queue.
- approved_at and approved_by: the date and the email of the admin who approved it. updated_at and updated_by for the last save of any kind.
- statement: the one sentence, in Jeff's fixed shape (section 8.3 of the guide shows it).
- raw_text: the paste, when there was one. Up to 8,000 characters.
- answers: the six answers, q1 to q6, up to 2,000 characters each.
- filters: what the queue uses. Industries as keys from a fixed list of ten (food processing, manufacturing, logistics, healthcare, benefits administration, TPA, professional services, financial services, technology, construction, plus Other with your own word), an optional industry pattern, the size band as a smallest and largest employee count, locations, ownership (PE backed, VC backed, founder or private, public, public sector), triggers, buyer roles in five slots (sponsor, budget, users, approvers, blockers), and disqualifiers (industries to exclude, a hard floor and ceiling on size, regions to exclude, and free text).
The document is the single source. The ICP page renders it, the queue filters on it, and the audit trail keeps the statement and filters before and after every approve.
6.2What the queue filters on today
When the document is approved, the universe rules of section 4 gain four filters that apply together:
- Industries. Each industry key maps to a word pattern that is matched against the company's industry text, case not mattering. The technology key matches "software", "saas" or "tech" but not "biotech" (this is the validated cut). When the document carries its own industry pattern, that pattern is used instead of the keys.
- Size band. The company's employee count must sit between the smallest and the largest. A company with no known employee count is left out, as it is today.
- Locations. When any location is given, the company's country or state must match one of them, whole or in part, case not mattering. When none is given this filter does nothing.
- Exclusions. Industries to exclude are applied as a pattern that removes matches. The floor and ceiling on size are hard bounds on top of the band.
Size fit changes with the band. Inside the band a company scores the full 25 for size. Within half the band's width outside it, 15. Further out, 8. The fit factor line on the brief names the band, for example "Size band fit (100 to 2,499 employees)". When a workspace has no approved document, the old rule stays exactly as it was (100 to 2,000, the former label) so no existing number moves.
The ICP page and the Today screen show why this many, five counts from the same build that fills the queue: the universe (companies that pass the industry, band, location and exclusion filters, before any evidence is looked at), those with at least one live observation, those that qualify after every gate (the pool the queue draws from), how many are shown (the top 40 at most), and how many sit at Tier 1, plus one sentence that explains the Tier 1 count. These are computed, never typed.
On Approve, the workspace's cached dataset is thrown away, on disk and in memory, and a rebuild starts in the background. The new filters show within a minute. No new web search runs; the app re filters and re scores what the lake already holds. Editing later and approving again does the same and bumps the version.
6.3Recorded, not scored
Three parts of the document are stored and shown on the ICP page but change nothing in the queue yet:
- Ownership. No company record in the lake carries who owns it, so PE backed, VC backed and the rest cannot filter anything. The page says "recorded, not yet enforced" next to it.
- Triggers. The events that make a buyer act. They will be matched to the signal catalog's evidence areas later, with a chip on desk rows and an optional boost in the queue order.
- Buyer roles. The five slots. They will feed the people section of the account brief once contact research lands in workspaces.
The private equity two tier rule (a sponsor running an AI program is a boost, a company already put through that program is a down rank) is shown as targeting rules on the page and is not applied to any score today. One more honest note: the line on the account brief that shows the company's revenue range was labelled "Ownership" until this release. It is labelled Revenue now, and the brief shows no ownership line at all, because no company record carries one.
6.4The gate and who sees what
Each workspace has a setup gate, on or off. A new workspace gets it on when the Axsys team creates it. Existing workspaces, the Meridian demo workspace among them, keep it off until they carry an approved document, so nobody is locked out by surprise.
With the gate on and no approved document:
- An admin who opens any app page is sent to the setup screen instead.
- A contributor or viewer sees a page called Almost ready: "Your admin is setting up who you sell to. The queue opens when that is approved." with links to Team and Guide.
- Team, Guide, Manual and Troubleshooting always open, so an admin can invite the colleague who holds the profile and everyone can read.
- The API is never gated. The isolation harness runs against the API and is not touched by the gate.
Who can do what, gate or no gate:
- Read. Every member reads the statement, the filters and the exclusions. Only admins receive the raw paste and the six answers; the app strips them for everyone else.
- Write. Only an admin can save a draft, ask for a prefill of a paste, or approve. A read only workspace (trial ended) cannot save at all.
- Seed. The Axsys team can load an approved document on a workspace, marked source "seeded", and can turn the gate on or off. The Meridian demo workspace is seeded by Axsys with a validated profile so it is never gated and shows a full list.
No AI writes the ICP in this build. The paste path is a plain word scan that fills the pickers for the admin to check. An AI assist that proposes filters and a sentence for the admin to accept comes after the pin, with its own daily cap and usage log.
6.5Your signals: switching a kind of event off
The ICP says which companies are in your view. The Your signals page (https://signals.srv1195619.hstgr.cloud/app/signals) says which kinds of event count once they are there. Each workspace can switch any catalog signal off, and every signal is on until someone does. Here is the rule, in order.
- The state. One row per workspace and signal in the signal state table: the signal's catalog key (the same key the desk's votes use), when it was switched off, who did it, and a reason. A signal with no row, or a row whose switched off date is cleared, is on. Nothing is stored for a signal nobody has touched, which is how "on by default" works.
- Where the drop happens. When the app builds your view (section 4), it reads the off keys for your workspace, pulls the observations, and drops every observation whose signal is off, right there, before the universe tests, before fit, timing and confidence, before the top 40 cut, and before any count. A company whose only observations are of off kinds fails test 5 of section 4.1 and leaves your universe. The Today tiles, the why this many counts, the desk's source library, the brief and the points are all built from what is left, so an off kind appears nowhere. On the desk that means an off kind is normally absent from the source library, because those rows are built from the results that survive; where a row for an off kind is still listed, it carries an Off chip and is dim.
- Per workspace. The lake is untouched. The observations still exist and other workspaces still see them. Your switches change nothing for anyone else, and theirs change nothing for you. Switching a kind back on brings its observations back on the next build. Off is not delete.
- When it shows. A flip throws away your cached view, in memory and on disk, the same way an ICP approve does (section 6.2), so the next page load rebuilds it. Allow up to a minute. The off keys themselves are cached for 60 seconds per workspace and cleared by the flip, so a workspace with no switched off signal builds its view exactly as before, byte for byte.
- Who. Admins and contributors, through the archive and unarchive endpoints (POST /app/api/signals/archive and /app/api/signals/unarchive, each with the signal key). A viewer is refused with forbidden. A read only workspace is refused with trial_expired. Every flip writes an audit row (signal.archive or signal.unarchive) with the person, the time and the network address; a flip to off stores the reason, which the page sends as "switched off on the Your signals page".
- What the page reads. GET /app/api/signals/choices, open to every member: the catalog's active signals for your volume (section 2.7), or all of them when the workspace has no volume, grouped by evidence area (the categories, seven today), each with its title, its what line, its catalog tier (T1 to T3, the signal's value, not the score tier of section 2.11), its weight (the points of section 2.16), its on or off state, and how many results of that kind are in your current view; plus whether you may edit, how many are off in total, and your volume.
- The Library is a different thing. The Library's Keep in set and Exclude write your Library set, and the Library's signals carry their own ids from Tommy's method. The map from those ids to the catalog keys is empty today, so a Library choice cannot reach the queue. Until that map exists, Your signals and Sources (section 6.6) are the only switches that change the queue, and the Library card says so under its two buttons.
Thresholds per signal (the line a value must cross to count) are a separate, later feature (section 7.4). A switch is all or nothing for a kind of event.
- Kinds we no longer collect. The page also lists catalog rows that are retired but still have at least one result in your workspace. They carry the chip "No longer collected", they sit under their own category, and their switch still works, so a workspace can stop counting old results of a kind nobody collects any more. Without this they were invisible and could not be switched off.
6.6Sources: switching a collection channel off
Your signals (section 6.5) says which kinds of event count. The Sources page (https://signals.srv1195619.hstgr.cloud/app/sources) says which of the channels we collect from count. A channel is one collector's output at the grain the lake records (section 3.1): the channel name is on every observation, the feed inside it is not. Every channel is on until an admin switches it off. Here is the rule, in order.
- The registry. A list in code, one row per channel, of what we really collect: the channel's key, its name, what it reads, how often it runs, the feeds beneath it (for display only), and the Library buckets it feeds. Each row also names the source tokens that observations from that channel carry, which is how the drop below finds them. The nine rows and their tokens:
| Channel on the page | Key | Source tokens on the observations | Runs |
|---|---|---|---|
| Google News and trade press | google_news | google_news_rss | every 8 hours, plus five themed passes overnight |
| SEC filings | sec_edgar | sec_edgar | overnight, once a day |
| Finnhub company news | finnhub | finnhub | every 8 hours |
| OSHA inspections | osha | osha | not running yet; it has never collected |
| Court dockets | courtlistener | courtlistener | overnight, once a day |
| Austin building permits | austin_permits | austin_permits | every morning at 07:00 UTC |
| Web research sweeps | web_research | re_research, web_sweep, client_growth, import_research | the Tavily sweep Mondays at 08:00; the other three when the team runs them |
| SBA loan records | sba_loans | sba | loaded in batches, last batch March 2026 |
| Financial profiles | financial_profiles | financial_layer, fmp_peer_compare | loaded in batches, last batch June 2026 |
The Runs column is from the collector schedules on 2026-09-06; the page's own cadence line is the live word. The web research row carries one more token, a retired one named after the client it was first run for; about 280 older observations still hold it, so it stays in the registry to keep those rows inside their channel, and every new row carries web_sweep.
- The state. The workspace record's dataset_config carries a sources_off list of registry keys. No list, or an empty list, means every channel is on. Nothing is stored for a channel nobody has touched, which is how on by default works. There is no new table or column: dataset_config is the same field the view builder already reads.
- Where the drop happens. When the app builds your view (section 4), it reads sources_off and drops every observation whose source token belongs to an off channel, right there, before the universe tests, before fit, timing and confidence, before the top 40 cut, and before any count: the same place the Your signals drop happens. An observation whose source token is in no registry row is never dropped; an unknown source stays in. A company whose only observations came from off channels fails test 5 of section 4.1 and leaves your universe.
- Per workspace. The lake is untouched and the collectors keep running for everyone. Your switches change nothing for anyone else, and theirs change nothing for you. Switching a channel back on brings its observations back on the next build. Off is not delete.
- When it shows. A flip throws away your cached view, in memory and on disk, the same way an ICP approve and a signal flip do (section 6.2), so the next request rebuilds it. Allow up to a minute.
- Who. Admins only, through POST /app/api/sources/toggle with the channel key and on (true or false). A contributor or a viewer is refused with forbidden; a read only workspace is refused with trial_expired. The page shows the switches disabled to anyone who is not an admin, with the note "Only an admin can change this." Every flip writes an audit row, sources.toggle, with the person, the time, the network address, the key and the new state.
- What the page reads. GET /app/api/sources, open to every member: the registry merged with your workspace's state, one row per channel with its key, whether it is on, its results in your current queue, the number not counted when it is off, and the date of its last result, with the feeds and the Library buckets beneath; plus can_edit (true for an admin in a workspace that is not read only), off_total (how many channels are off), the Library buckets no collector reads yet, and your workspace's own Library rows.
- What the counts mean. Results in your queue: observations from this channel that survived every drop and sit in your current view. Not counted: shown when the channel is off, every observation from it on a company inside your universe filters (before the top 40 cut and the per account cut), so it can be larger than the results number was while the channel was on. Last result: the date on the newest observation from this channel among your companies, on or off. A channel with zero results and an old date is quiet for your companies, not broken (section 3.6).
- One feed inside a channel. Off is per channel. The feeds under Show the N feeds are display only, because the lake records the channel and not the feed (section 3.1). A switch per feed waits for feed level tracking in the collectors. The rows under "In the library, not collected yet" have no switch either: nothing is collected from them, so there is nothing to switch.
- Sources and Your signals together. An observation counts only when its kind is on (section 6.5) and its channel is on. The two drops are independent, and both happen before scoring.
6.7Your own sources, the CSV import and the starter sets
The registry in section 6.6 is what Axsys collects. This section is how a workspace writes down places we do not read yet. Admins and contributors can add; viewers read the list. Nothing new was added to the database: each one is a row in the shared data_sources table that belongs to your workspace through its origin, client:<your short name>.
- One at a time. POST /app/api/sources/own with a name, a url, an industry key or blank, notes and, when the site wants an account, a tick and a line saying what kind of login it is. The checks: the name is 2 to 120 characters; the url starts with http or https, has a host name with a dot, carries no user name or password, and does not point at a private network, a loopback or a local machine; the industry is one of the ten vocabulary keys or blank; the notes are 500 characters and the login line 200. A password is never asked for and must never be typed. Two rows with the same host and path, once the case is folded and a trailing slash dropped, are the same source for one workspace, and the second is refused as a duplicate.
- What is written. The row's key is
client:<short name>:<12 characters of a hash of the host and path>; kind isclient; cadence isqueued; the notes go in cost_note; the login line, when there is one, goes in access_note as "Behind a login: ..."; the industry key goes in causal_synopsis; origin isclient:<short name>. Auditsources.addon data_sources with the key. - What queued means. Written down, with the person and the date, and read by nothing. No collector visits that address tonight. It is a line in the queue for the Axsys team to wire up, one source at a time. The page and the guide say it in those words, because the honest state is better than a promise.
- Many at once. POST /app/api/sources/import takes the raw text of a CSV file. A header row is required, in any order:
name,url,industry,notes,behind_login,login_note. Name and url are needed, the rest may be blank, and any other column is ignored. Data rows are numbered from 1 in file order; a blank line keeps its number and is skipped. The cap is 500 data rows: row 501 and beyond are rejected with "over the cap", and the reader stops at row 2000. A body over 2 MB is refused. Every row gets the checks above, plus two more: a repeat inside the file reads "duplicate of row N", and one you already have reads "already in your workspace". The answer lists the accepted rows and the rejected ones with the row number and a plain reason, so a person can fix the file and import again; importing twice does no harm, because what is already there is skipped. One audit row,sources.import, with the two counts. - The starter sets. A staff tool,
tools/build_starter_sets.py, asks Claude once per industry for 15 to 20 sources worth reading (its own model constant, its own token cap, the usage printed per call) and writesdocs/signals/starter-sets/<industry>.jsonwithreviewed: false. Jeff or Tommy read the file and mark it reviewed; a staff run with--load <industry>on the box then writes the rows as data_sources with originstarter:<industry>. The tool refuses to load a file that has not been reviewed, and nothing in the app ever calls it. - The cap. All three ways of writing a source share one bucket: 60 writes an hour per workspace, not per person, counted on the workspace id. A CSV import is one write no matter how many rows are in it, and so is applying a starter set. Past the cap the endpoint answers 429 and the card says "Slow down a little." Nothing is lost but the press. The same shape of cap guards Send to CRM (section 8.3) and Report a problem (section 11.3).
- Applying a set. GET /app/api/sources carries a starter block: the industry (the first industry key in your ICP, or the industry on your workspace, or none), its name, how many rows exist for it, and whether you have applied it. The block is named after the ICP's first industry, so it follows the ICP privacy switch: in a workspace whose admin keeps the ICP private, a member who is not an admin gets an empty block and no industry at all, the same way the ICP itself is cut down for them (section 6.9). The admin still sees the band, and applying a set is unchanged, because that request carries the industry the caller names. POST /app/api/sources/starter copies every row of that set into your workspace as your own queued rows, key
client:<short name>:starter:<industry>:<n>, with the note "From the <name> starter set" and the one line reason each was picked. Rows you already have, by key or by url, are skipped, so pressing the button twice adds nothing. Auditsources.starterwith the industry and the count. Until a set is loaded on the box, the count is 0 for every industry and no band shows on the page.
None of this moves your queue, so nothing here throws your built view away: a queued source produces no results.
6.8What produced results
The view builder writes, for every registry channel, two windows next to the counts section 6.6 already uses:
| Key | What it holds |
|---|---|
w7 | observations, accounts, last, off, over the 7 days up to the build date |
w60 | the same, over 60 days |
- The population. The observations of the companies in your universe, taken before the 8 per account cut, so this counts what a channel found for you and not what the queue happened to show. Each observation is mapped to a channel by its source token; a token in no registry row is counted nowhere.
- The window. The observed date must fall inside the 7 or 60 days up to the build date. A date in the future does not count.
- The numbers. Observations is how many results the channel produced. Accounts is how many different companies those results were about. Last is the newest date inside the window, or nothing.
- Off channels. Their observations were set aside before any counting, so both windows read zero with off true, and the row's note says "Off for this workspace".
GET /app/api/sources/performance?window=7|60, open to any member, answers the rows ranked by observations, ties broken by name, each with its rank and a note that is blank, "No results in the window" or "Off for this workspace". No audit, no throttle, no write. Every registry channel gets a row even when it has nothing.
What this card cannot say is whether a channel ran at all. Zero results can mean "it ran and found nothing for you" or "it never ran". That is the Health page (section 3.6), per collector today with each row titled by its channel, one row per channel next, and per feed after feed level tracking.
6.9Who may see the ICP
The ICP document is the workspace's plan, and some admins do not want every member reading it. One switch on the Team page decides.
- The state. dataset_config.settings, one key,
icp_hidden, true or false. Visible is the default, and nothing is stored until someone flips it. - Who flips it. POST /app/api/settings with
{"icp_hidden": bool}, admins only, refused in a read only workspace. Auditsettings.updatewith the new value. GET /app/api/me carriesicp_hiddenandsettings_can_edit. - What hidden does. For a member who is not an admin: GET /app/api/icp answers 403 with "hidden"; the ICP block injected into the page and the statement in the view's meta are cut down to
{"hidden": true}; the ICP page shows one line, "Your admin keeps the ICP private.", and none of the document, the counts or the Edit button; and the shell drops the ICP item from the rail. The starter set band on Sources goes with it, because that band is named after the ICP's first industry (section 6.7). An admin sees the document as before, with a small "hidden from members" chip on the ICP page and beside the switch on Team. - What hidden does not do. Nothing in the queue, the filters or the scoring changes. The document still decides who is in your universe. Hiding it changes who may read it, and that is all.
7.Calibration and feedback
7.1What a vote does today
There are two kinds of vote, and they are stored in the same table.
- A stamp on a kind of signal. On the Signal desk you give a signal type a value from 1 to 5 with a why of up to 280 characters. One row per person, per workspace, per signal type.
- A verdict on a lead. On the desk rows and on the account brief, Good lead or Bad lead marks one company, with one or more reason codes and a why of up to 240 characters. One row per person, per workspace, per company, kept under the key
lead:<company id>, with the verdict as 1 for good and -1 for bad, no 1 to 5 value, and the comment stored as "<reason>: <why>", where the reason part is one code or several joined by commas in the order the list below gives them ("good_fit,good_timing: <why>"). Since release 0.5.1 the endpoint takesreasons, a list; a lonereasonis still accepted, so a page opened before the release keeps working. The vote table holds 280 characters for the reasons and the why together, so a verdict with many reasons and a full why can pass it; that is refused withwhy_too_longand the number of characters left for the why, and never cut short. Saving again with the other button changes your mind in place, because the row is unique on the workspace, the person and the key. The nine reason codes are good_fit, good_timing, strong_evidence, not_a_fit, wrong_size, wrong_industry, old_news, already_customer and other. The picker never shows all nine at once: Good lead offers four (good_fit, good_timing, strong_evidence, other) and Bad lead offers six (not_a_fit, wrong_size, wrong_industry, old_news, already_customer, other), with other on both. The endpoint accepts any of the nine with either verdict; the narrowing is the page being kind, not a rule in the data.
Who may vote: admins and contributors. Viewers see the tallies and get no buttons. A read only workspace cannot vote at all. Each person can save up to 240 votes an hour, both kinds together; past that the page says "Slow down a little". Every save writes an audit row, lead.vote for a verdict. GET /app/api/leads/votes answers two things: your own verdicts, and the team tally per company as a count of good and bad, with no names.
What happens next: nothing, by machine. No rule changes, no weight moves, no score shifts. The desk, the brief, the guide and this manual all say the same sentence, "Saved for the Axsys team's weekly review. Nothing in the scoring changes by itself." A hundred Bad leads do not move a score. A person reads them each week and decides (section 7.2). The older wording that said ratings "feed back into scoring" or "train the model" was removed on 2026-09-04.
One detail for whoever wires a client: the identifier the page sends for a lead is the real company id when the result rows carry one, and the account's short id when they do not. The handlers accept either.
7.2The weekly review
The Axsys team reads the votes and the whys by hand, each week. Any change to a rule, a weight or a threshold is made by a person and written to the audit trail. Nothing in the scoring changes by itself. A worker that rolls votes up per signal, category and source into a weekly packet for Jeff and Tommy comes once Jeff sets the rules for what a vote may change.
7.3Per result votes (still to come)
A verdict marks the company, not the line you were looking at. If two results belong to the same company, both show the same verdict, and that is on purpose while the vote key names a company. A vote per result, so that a Bad lead can mean that one piece of evidence, needs a database change and waits with the rest of them.
7.4Thresholds (later)
A place to set, per signal, the line a value must cross to count (five percent over, five percent under), with the old and new values audited and a Re run button that re scores existing observations. It waits on Tommy's written definition of a good lead with upper and lower bounds. The swept 1,700 lead set is the calibration sample. Re run never re searches the web.
7.5The Discovery questionnaire and the Workshop
Both screens remain reachable and both are optional. They are the deep discovery path from Tommy's method, and they are off the main path for the MVP. Nothing in the queue reads them today. If your workspace answered questions there, the answers are kept.
8.Getting leads out
A lead leaves the app in three ways, all carrying the same thing. The shape is version 1 and it is written down in docs/signals/crm-payload-v1.md in the product repository; that file, with its worked example, is the contract, and this section is the summary.
8.1Three ways out
- Download CSV. One lead as a header row and one data row, 71 columns, with the evidence flattened into numbered columns (evidence_1_title through evidence_8_url). Opens in a spreadsheet as it is. Any member may download.
- Download JSON. The same lead as one object. Any member may download.
- Send to CRM. The same object posted to the webhook address an admin saved on the Team page. Admins and contributors may send. A viewer is shown the button, disabled, carrying the reason "Only an admin or a contributor can send." as its title, which is the same treatment the source switches get: the door is visible and shut, not hidden.
The buttons sit on the account brief and in the Today drawer. A download is GET /app/api/export/account?id=<company>&format=json|csv, comes back as an attachment named axsys-<short name>-<company>.json or .csv, and writes an audit row export.download with the format. A workspace whose trial ended may still download; it may not push.
8.2The payload, field by field
Every key is always there. When we do not know a value it is null, never missing, so a mapping on the far side never breaks when a field is empty.
| Part | What it holds |
|---|---|
version | Always "1" for this shape. |
sent_at | When we sent it, UTC. |
workspace | Your workspace: its short name and its display name. |
account | The company: id (the same id as the brief link), name, domain, headcount, industry, hq. |
scoring | score, score_max (the scale it is out of: 85 when size is not scored, 100 otherwise), tier 1 to 4, tier_label, band (SMB, Mid-market, Enterprise), fit, evidence, timing, confidence, and why. why is built by _why in signals_export.py straight from the engine factors, not from the why block: it is each term's engine label with its points, joined with full stops, like "Evidence breadth (distinct evidence areas) 20 of 20. ...". Same arithmetic as the card on the screen, none of its plain words. evidence and score_max were added in 0.4.0 as new keys; the CSV columns are unchanged. Putting the block's sentence in the payload would be a version 2 change. |
top_signal | The newest piece of evidence: id, title, date and the excerpt. |
evidence | Up to 8 results, newest first: signal_id, title, date, channel, url (a link when we have one, else null) and excerpt. |
links.brief | The account brief in Axsys Signals. |
No people and no contacts are in a lead. Contacts wait on a privacy decision. The evidence link and the excerpt fill in as the evidence links work reaches older rows (section 2.4). Adding a field is a version 2 change, written in the contract file first, never a quiet addition.
8.3The webhook
- The state. dataset_config.integrations holds webhook_url, webhook_secret, created_at, last_push_at and last_push_status. Clearing it writes an empty object, so "no webhook" is simply no url.
- The secret. 32 hex characters, made by the server when an address is saved. It is returned once, in the answer to that save, and never again: not in a page, not in the read back, not in the audit detail, not in a log line. The read back shows its last four characters only. Saving an address again always makes a new secret, which is the only way to rotate one. Losing it means saving the address again.
- Which addresses are refused. https only; a host name with a dot; no user name or password in the address; no IP address written out; not localhost, not a .local or .internal name, not our own hosts. The name is resolved and refused when any address behind it is private, loopback, link local or a cloud metadata address. The check runs when the address is saved and again before every send, so an address that later resolves inside a private range is never contacted.
- The endpoints. GET /app/api/settings/webhook (admins only) reads the url, the last four of the secret, and the last push. POST /app/api/settings/webhook (admins only) saves or, with an empty url, clears; a refused address answers 400 with a plain reason the page prints under the field. POST /app/api/settings/webhook/test sends a small test message. POST /app/api/export/push sends one lead. Both pushes share one bucket, 60 an hour per workspace. There is a second, smaller limit that is about the server and not about you: the whole app makes at most eight pushes at once, counting every workspace. A push that arrives when all eight are busy is not queued; it answers at once with "Too many sends are in flight right now. Nothing is queued; wait a moment and press again." A push waits up to eight seconds for the CRM, so a slot is rarely held for long.
- The audit.
settings.webhookfor a save, a clear or a test, with the host and the last four of the secret and never the whole address, because a catch address from a no code tool is itself a secret.export.pushper lead with the company, the status and whether it worked. - No retry. A push waits up to eight seconds for an answer. It either arrived or it did not. Nothing is queued, nothing is tried again in the night, and the screen says so: "The push failed: (the reason). Nothing is queued; try again." The Team page carries the last push time and status so an admin sees the same thing. A retry queue is on the later list.
8.4The signature
Every message carries three headers besides the content type: X-Axsys-Event (lead.push or lead.test), X-Axsys-Timestamp (the unix time in seconds when we signed it) and X-Axsys-Signature (sha256= and 64 hex characters). The signature is an HMAC with SHA-256 over the timestamp, a dot, and the exact bytes of the message, keyed with your secret. The far side does the same sum with the same secret and compares the two strings; if they match, the message is ours and was not changed. A timestamp more than five minutes old should be thrown away, so an old message cannot be replayed.
Most no code tools cannot do that sum. For them the address itself is the secret, because the long random part of a catch address is what keeps strangers out. A team with its own small service in front of the CRM checks the signature there.
8.5The recipes
Three step by step recipes live in docs/signals/crm-recipes-2026-09-05.md: Zapier into HubSpot, HubSpot's own webhook trigger, and Salesforce by Zapier or by a Flow. One honest line, printed at the top of that file and repeated in the guide: they were written from the vendors' documentation and have not yet been tried on a trial account. The first customer who follows one tells us what did not match, and the file is corrected.
9.Roles
Every member has one of three roles. Whoever invited you picked it. Checked against the code on 2026-09-04.
| Role | What you can do |
|---|---|
| Viewer | Open every screen, search, open briefs, read the Library, read Health, see the team list. Stamp a signal type 1 to 5 on the desk, and see the Good and Bad lead tallies. Download a lead as CSV or JSON. Report a problem. Cannot vote Good or Bad lead, send a lead to a CRM, add a source, or flip a switch on Your signals or on Sources. (The Team page says only contributors rate; the code lets viewers stamp a signal type too. The code wins, and the wording is on the list.) The ICP page is theirs to read unless an admin hid it (section 6.9). |
| Contributor | Everything a viewer can, plus: switch a kind of event on or off on Your signals (section 6.5), keep or exclude a signal in your set, add a signal of your own to the Library, start and answer the optional Discovery questionnaire. Cannot flip a source switch on Sources; that is an admin's (section 6.6). Also: vote Good lead or Bad lead with a reason (section 7.1), send a lead to the CRM (section 8), add their own sources, import a CSV and apply the starter set (section 6.7). |
| Admin | Everything a contributor can, plus: invite people and revoke invites, see pending invites, change roles, remove members, decide the Workshop, read the audit trail (through the API; there is no screen for it yet), set up, edit and approve the ICP (section 6), and switch a collection channel on or off on Sources (section 6.6). Also the two workspace settings: whether members may see the ICP (section 6.9) and the CRM webhook, its secret and its test (section 8.3). |
| Any role, once the trial has ended | Reading is unchanged for every role. Writing is refused with "This workspace is read-only. Contact Axsys to continue." Three writes are allowed on purpose; the table below says which. |
A workspace whose trial has ended is read only, and that is not quite the same as "nothing can be written". Three things still work, deliberately, because none of them changes the workspace's own data or spends anything: you can still get your leads out as a file, still tell us something is wrong, and still finish the tour so it stops opening. Checked against the code on 2026-09-06.
| In a read only workspace | Still works | Why |
|---|---|---|
Download a lead, GET /app/api/export/account (section 8.1) | Yes, for every role | The data is already yours to read on the screen; the file is the same data in another shape. A push to a CRM is refused, because that leaves the app. |
Report a problem, POST /app/api/report (section 11.3) | Yes, for every role, up to ten an hour | Telling us the product is broken must never depend on the trial being live. It writes an issue for the Axsys team, nothing in the workspace. |
Mark the first login tour as seen, POST /app/api/tour/seen (section 3.5 of the guide) | Yes, for every role, up to five an hour | It only records that you have seen the tour, so it stops opening. Refusing it would reopen the tour on every page. |
| Everything else that writes | No | Votes, verdicts, switches on Your signals and Sources, your own sources and imports, the ICP, invites and role changes, the workspace settings, the webhook and Send to CRM are all refused with trial_expired. |
The Team page's role picker says an Admin "manages people, workspace settings and the ICP". That matches the code: only an admin can save, prefill or approve the ICP document (section 6.4). The viewer line above still says less than the screens do: viewers can rate.
Two more people you will hear about.
- The gold owner is one admin per workspace, the first admin who accepted the invite. The gold owner can never be removed without a handover to another member.
- Axsys staff create the workspace and the first admin invite, extend a trial, change workspace status and load the Library. They do not appear on your Team page unless invited. They run the platform and can see the database for support. Section 10 says what that means.
Three rules that look like errors and are not. The last admin cannot be demoted or removed; promote someone else first. A workspace whose trial has ended goes read only for everyone: reading works, writing is refused, except for the three writes in the table above. And if you expect a button and it is not there, this is almost always your role, not a mistake.
10.Data, privacy and retention
10.1What is stored for your workspace
- The workspace record: name, short name, status, trial end date, industry, and the settings from section 6.1.
- Members and their roles. Invites, stored as a hash of the link, with the sent and expiry dates and whether they were accepted or revoked.
- Votes, values and whys, attributed to the person who wrote them.
- Your Library choices (keep or exclude) and any signal you added.
- Your signal switches: which kinds of event are off for your workspace, who switched each one off, when, and the reason (section 6.5).
- Your source switches: which collection channels are off for your workspace, kept as a list of channel keys in the workspace record (section 6.6). Who flipped each one, and when, is in the audit trail.
- Discovery answers and Workshop decisions, if you used them.
- The audit trail (section 10.4).
- Your own sources, the ones you added by hand, by CSV or from a starter set, as rows that belong to your workspace by their origin (section 6.7).
- Your CRM webhook address and its signing secret, and the time and status of the last push (section 8.3).
- Your Good lead and Bad lead verdicts, with the reason and the why, attributed to the person who saved them (section 7.1).
- A cached copy of your built view, in memory and on the server's disk, trusted for 60 minutes and thrown away by name whenever something that changes it happens (section 4.4).
All of the workspace settings live in one field on the workspace record, so nothing here needed a new table or a new column:
| Key in the workspace record | What it holds |
|---|---|
icp and icp_required | The ICP document and the setup gate (section 6.1). |
volume, line, statement | Which model your workspace is scored with, set by Axsys staff. |
sources_off | The channel keys your admin switched off (section 6.6). |
settings | Today one key, icp_hidden, true or false (section 6.9). |
integrations | The webhook address, its secret, when it was made, and the last push time and status (section 8.3). |
The secret is the one value in that field that never leaves the server after the moment it is made.
10.2What is shared, and what is not
The companies, the signals and the observations are the Axsys research lake. Every workspace reads the same lake. Each sees its own slice. Nothing your workspace does changes the lake, and no other workspace can see your members, your votes, your set or your answers. The Library catalog is shared. A signal you add is visible only to your workspace. A source you add is private to your workspace too: the rows sit in the shared source table, and only your workspace reads the ones whose origin names it (section 6.7).
10.3One users table with the CRM
This product and the internal Axsys CRM share one users table. That is why one password serves both, why a reset here changes your CRM password, and why an invite accepted here works with an existing Axsys password. An account created by invitation here is marked as a tenant account and is refused by the CRM's sign in. This is on purpose.
10.4The audit trail
Every write that matters is appended to an audit log that is never edited: password resets, invites created, accepted and revoked, members removed or given a new role, the gold owner handed over, votes saved and cleared, Library choices and additions, signal and source switches, Discovery and Workshop actions, and every staff action on your workspace. Each row carries the time, who did it, what was done, what it touched, and the caller's network address. Admins can read the last 100 rows through the API. There is no screen for it yet.
The 9/05 build added these actions:
| Action | Written when | What the detail holds |
|---|---|---|
settings.update | An admin flips "Members can see the ICP" | the new value |
sources.add | Someone adds one source of their own | name, url, industry, whether it is behind a login |
sources.import | A CSV import finishes | how many were accepted and how many rejected |
sources.starter | A starter set is applied | the industry and how many rows were added |
export.download | A lead is downloaded | the format and the company |
export.push | A lead is pushed to a CRM | the company, the status, whether it worked, the first 200 characters of any error |
settings.webhook | A webhook is saved, cleared or tested | which of the three, the host, the last four of the secret, the test status |
lead.vote | A Good lead or Bad lead verdict is saved | the company, the verdict and the reasons (reasons, with the first one also as reason) |
tour.seen | The first login tour is finished or skipped | the tour version and which of the two |
issue.report | Someone sends Report a problem | the issue row it created |
access.request | Someone asks for access on the public form | name, email, company, what they sell, and whether the email is a free one. This is the one action with no workspace and no user, because the person is not signed in. |
Beside the audit log the server keeps a structured event log for the operators. One line in it is worth naming here: when a browser goes away in the middle of a request, usually because someone closed the tab or a download was cancelled, the server writes http.client_gone with the path and stops. It does not write an error page to a socket that is gone and it does not print a stack trace, because that is a person leaving, not a fault.
10.5Isolation in two layers
Layer one is the application. It reads and writes the database only through a short allow list of tables and always adds your workspace id. A harness of 29 probes tries to cross from one workspace into another and must fail every time. It passed before and after the second layer was installed.
Layer two is the database itself. Row level security is installed on 25 tables so that, once armed, the database refuses a row from another workspace even if the application asked for it. It was armed and verified on September 1: a token for the right workspace returns its rows, a token for another workspace returns nothing, and a forged token is refused. The harness proves layer one on every release; layer two stands behind it.
10.6Backups
The database provider takes a backup every day. An off site copy and a timed restore drill are on the list, and the recovery targets (how much data could be lost, how long a restore takes) wait on sign off from the Axsys leadership team. Until the drill has run, a restore has not been proven. Said out loud, because it matters.
10.7Retention
Nothing is purged automatically today. Planned: a 90 day purge of event logs, a 30 day purge of archived rows, and a rule for how long the network address stays on audit rows. Sessions end after 30 days of use, or 90 days at most. Reset links last one hour, invite links 14 days, and observations carry a 180 day shelf life for the scorer.
10.8The privacy notice (coming)
A product privacy notice and a list of sub processors, mapped to the Axsys privacy policy clause by clause, will be linked from the sign in page, the guide and the marketing footer. Until then, one fact for your security team: on these pages your browser talks to our server and to Google Fonts for the typefaces, and to nothing else. No analytics, no session replay, no third party scripts. The database region and the server datacenter will be recorded in the notice.
11.Releases
11.1The stamp
Two versions are in play and they are not the same number. The product is on release 0.5.1; that is the build you are signed in to, and it is the one to quote when you report a problem. This manual is on edition 0.6, built 2026-09-28, and that number is stamped at the top and the foot of this page. An edition describes a release; it does not name it.
11.2What happens at each release
Every release goes through a gate on a staging copy before it reaches you: isolation, regression, screen and fail soft checks. The gate also checks the documentation: every screen has a guide chapter, the numbers in this manual equal the constants in the code, the help pages answer without a sign in, and no dashes have crept in. Release notes are emailed to everyone at every release, with a paragraph on what changed in the words.
11.3How to report a problem
A Help button sits at the top right of every signed in page, beside Take the tour. Its menu has four entries: the guide chapter for the page you are on, Take the tour, Troubleshooting, and Report a problem. The round "?" that used to float in the bottom right corner is retired, because it covered a switch on Sources, Remove on Team and a filter chip on a phone.
Report a problem opens a small form: a title of up to 120 characters, what happened in up to 2,000, and the page path, filled in for you. Any member may send one, up to ten an hour, in a read only workspace too (section 9). POST /app/api/report writes one row in the Axsys issue table with the title prefixed "[Signals]", the body prefixed with the workspace, the person's email and the path, the area "signals", the category "product", the status "open" and the sender's email as the reporter. It also emails the Axsys team when the mail sender is set on the box, and writes the audit action issue.report. The screen answers "Sent. Reviewed on Thursdays."
That last sentence is the promise and it is kept by people: the reports land in the same list the CRM's issues use, and the team reads them on Thursdays. Nothing is read by a machine and nothing changes by itself.
Outside the app, the public troubleshooting page at https://signals.srv1195619.hstgr.cloud/help/troubleshooting needs no sign in, the person who invited you, or the Axsys team at jonathan.bayo@axsys.ai takes anything else, and https://signals.srv1195619.hstgr.cloud/status says whether the trouble is ours. Error pages show a short "Reference" code; send it with the exact words on the screen.
12.MVP scope
12.1In this build
- Sign in with email and Axsys password, forgot and reset by email, invitations with a 14 day link, three roles and a gold owner.
- The Today queue: top 40 accounts, four tiles, five filters, search, a "Biggest gap" line on every row that is short on something, and the drawer with the reason, the why this score card, the account facts and the timeline.
- The account brief with the why this score card across the full width, the timeline, the account facts and the signal mix. The card gives the sentence, a row per part of the score with what it earned against what was on offer, the score on a double rule, and what would move the account up (section 5.4).
- The Signal desk: a verdict per lead with one reason or several, four chips under Good lead and six under Bad lead out of nine codes in all, and a why, 1 to 5 values per signal type and whys, team averages and tallies, an honest last result date per row, and a Source link on every result that has one.
- The Library: categories, signals, sources, chains, grades per industry, keep or exclude, add your own signal.
- The ICP page and the ICP setup flow: one question then six or a paste, review, approve, Edit later, the why this many box, and the setup gate for new workspaces. Targeting rules are shown, not applied.
- The Your signals page: every catalog signal for your volume by category, a switch per signal and All on or All off per category, on by default, off dropped before scoring for your workspace only, and the links to it from the desk, the Library and the ICP page. The setup flow passes through it on the way to Sources.
- The Sources page: the nine channels we collect from, one row each with its cadence, its feeds, its Library buckets, its last result and its results in your queue; a switch per channel for admins, off dropped before scoring for your workspace only; and the read only list of Library buckets no collector reads yet. The setup flow ends there, by the Next: Sources link on Your signals.
- Sources, the rest: your own sources one at a time or 500 in a CSV, the industry starter sets, and the What produced results card over 7 and 60 days (sections 6.7 and 6.8).
- Getting leads out: Download CSV, Download JSON and Send to CRM, with the version 1 payload, a signed webhook an admin sets on the Team page, and no retry (section 8).
- The Health page: three windows with the longest one clamped to the run history we really hold, one plain sentence per collector, each row titled with the collector's own name, the reason codes of Appendix B, and the honest "Health needs the n8n key" state when the box has no key (section 3.6).
- The Team page: invite, roles, pending invites, gold owner handover, and the Workspace settings card with the ICP privacy switch and the CRM webhook.
- The tour: five steps on Today, or three when the workspace has no accounts yet, starting by itself on a first visit and startable again from the Take the tour button at the top right of every page, with the Help button beside it and Report a problem inside it (section 11.3).
- The public Ask for access form at https://signals.srv1195619.hstgr.cloud/request, and the marketing pages pointing at it (section 1.4).
- The optional Discovery questionnaire and Workshop.
- The help pages: the guide, this manual and the troubleshooting page, public at https://signals.srv1195619.hstgr.cloud/help with no sign in, and inside the app at /app/guide, /app/manual and /app/troubleshooting.
- The nightly run: the sync and the rescore at 06:30 UTC every morning, incremental, with the carried stamp on the desk and on the status page (section 3.5).
- The public status page, fail soft pages during an outage, the 60 minute cache with a disk copy.
12.2Planned next, not in this build
- Scoring on the ownership, triggers and buyer roles recorded in the ICP document.
- The Library's Keep and Exclude reaching the queue, once the Library's signal ids are mapped to the catalog's keys. Today Your signals and Sources are the only switches that change the queue (sections 6.5 and 6.6).
- Feed level tracking in the collectors, which is what a switch per feed on Sources and a Health row per feed both wait on (sections 6.6 and 3.6).
- Collecting from a source a workspace added. Today it is written down and queued, and nothing reads it (section 6.7).
- A retry for a failed push, and native HubSpot and Salesforce connectors.
- Votes per result, so a Bad lead can mean one piece of evidence (section 7.3).
- A screen for the audit trail.
12.3Explicitly deferred
- Automatic fixes on a failed collector. Health says what happened; a person still fixes it.
- Thresholds per signal with audit and re run (waits on the lead definition).
- The feedback loop worker (waits on the feedback rules).
- The help bot (waits on a ruling; the product's own assistant stays internal until then).
- Native HubSpot and Salesforce connectors.
- Deep discovery: the session rail, the question review and the verdicts are parked.
- Holding a login or a paywall subscription on a workspace's behalf.
- AI suggested sources per workspace.
- Contacts and people on the brief (waits on a privacy decision).
13.Known limitations and open items
Honest, as of this edition.
- The desk's "Source library" is a list of signal types, not places we read. Its 1 to 5 ratings are ratings of signal types.
- The desk's status column now reads "Last result <date>" or "No results yet", and paints green only inside seven days. Whether the collector ran is on the Health page, not there.
- "Strongly Supported" comes from the catalog's mode for the signal type, not from the evidence we read. "Verified" is described in the model table and never assigned.
- A workspace with no approved ICP document still rewards 100 to 2,000 employees for size, so there a 2,001 to 2,499 employee company cannot reach the full size score. Once an admin approves a document, the band in that document is used instead (section 6.2).
- One scale has three names: Tier 1 to 4, Pursue now to Low priority, and Surging, Heating, Monitoring. Monitoring covers Tiers 3 and 4; the status word Monitor covers Tier 3 only.
- A Good lead or Bad lead verdict marks the company. A 1 to 5 stamp marks the signal type. Neither marks the one result you were reading (section 7.3).
- Viewers can stamp a signal type 1 to 5 on the desk. The Team page says only contributors rate.
- Keep or exclude in the Library changes your set and does not change the queue today. The switches on Your signals and Sources do (sections 6.5 and 6.6). The Library's signal ids and the catalog's keys are two lists with no map between them yet.
- A source switch is per channel. One feed inside a channel (one newspaper) cannot be switched off yet, because observations record the channel and not the feed (section 6.6).
- Targeting rules are shown on the ICP page and not applied to scores.
- Nothing takes points away.
negativeis 0 andnegativeSignalsis empty on every account, which is why the why card's rows total the score exactly (section 5.4). - The lead payload carries the engine labels line as its
why, not the why block's plain sentence. Adding the sentence is a version 2 change (section 8.2). - Ownership, triggers and buyer roles in the ICP document are recorded and shown, not scored. Only industries, the size band, locations and exclusions change the queue (section 6.3).
- Evidence links are carried on new results and filled in on older ones a few thousand a night, so some results still say "no link on file" (section 2.4).
- Some real events never become observations by design (section 3.3, step 5).
- An observation stays in view as long as it is marked active. The app does not apply the scorer's 180 day shelf life.
- The "Thin evidence" filter is not the provisional flag.
- The audit trail has no screen. Admins read it through the API.
- The database's second isolation layer is armed; the automated harness proves only the first layer on each release, so a probe for the second is still to be added.
- The guide, this manual and the troubleshooting page are public at https://signals.srv1195619.hstgr.cloud/help and inside the app, and the help button opens them from every signed in page.
- Health is per collector, not per feed, and it cannot tell "the sources had nothing" from "they had things, none about you" (section 3.6).
- A Health row can only claim a result from a channel it is the sole writer of, because results are recorded per channel and not per collector. A collector that shares all of its channels says so rather than claiming the channel's finds (section 3.6).
- A Health answer that runs out of its 20 second budget comes back partial: the rows it did not reach say so, and the four tiles count only what it did reach. A reload finishes it (section 3.6).
- Health needs two settings on the box. Without them the page says so and shows nothing else.
- A failed push to a CRM is not queued and not retried. You press the button again (section 8.3).
- The three CRM recipes were written from the vendors' documentation and have not been tried on a trial account (section 8.5).
- A source a workspace adds is queued and nothing collects it (section 6.7).
- The universe is the companies the lake already knows. Adding new companies waits on a go from Axsys. Nothing a workspace does creates a company row.
- Grades in the Library come from a synthetic backtest, not from results.
- Lead time and shelf life per signal in the Library are not loaded for every signal and are not used in scoring.
- A lead leaves as a CSV file, a JSON file or a webhook message. Nothing else leaves the app.
Appendix A.Field reference by screen
One line per field. The guide has the longer version with what to click next.
A.1 Sign in, forgot, reset and invite
| Field or message | What it is |
|---|---|
| The address you were invited with. | |
| Password | Your Axsys password. New users set one of at least 10 characters when accepting an invite. |
| Forgot password | Emails a reset link that works for one hour, up to three times an hour per email. The reply is always "Check your email", whether or not the address is known. |
| Wrong email or password | Exactly that. Try again slowly. |
| Too many attempts | Ten tries on one email inside an hour, right or wrong, or ten from one network address in fifteen minutes. The email lock lasts up to an hour, the address lock fifteen minutes. A password reset clears both. |
| Link expired | A reset or verification link is past its time or was already used. Ask for a new one. An expired invitation shows "Invitation not valid" instead. |
| Signed in as someone else | You opened an invite for one email while signed in as another. Sign out, then open the invite again. |
| No workspace yet | Your account exists and belongs to no workspace. Open the invite email if you have one. Otherwise ask the person who invited you. |
| Choose a workspace | You belong to more than one. Pick one. |
| One moment | The database is slow or down. Wait a minute and try again. The status page says more. |
A.2 Today
| Field | What it is |
|---|---|
| Signals caught this week | Results (the observations shown) whose own event date falls in the last seven days. It counts the day the event happened, not the day the row was written, so the tile and the list under it count the same things. |
| Accounts scored | The number of accounts in your view, at most 40. |
| Surging now | Accounts with a score of 80 or more. |
| New this week | Accounts whose company record was created in the lake in the last seven days. That is the day Axsys first met the company, which is not always the day it reached your queue. |
| This week's movers | Filter: accounts with at least one result dated in the last seven days. This is the default. |
| All accounts | Filter: everything in your view. |
| Pursue now | Filter: Tier 1 only. |
| Thin evidence | Filter: accounts with one shown result or none. |
| Search | Matches the account name, its industry, and the text of its results. |
| Account, why it moved | The name, and either the newest result or "N signals this week" with the signal names. |
| Biggest gap | why.short, the few words for the factor with the largest gap, printed under the reason line, for example "no timing estimate yet". Absent only when no factor is short, not when the account is Tier 1 (section 5.4). |
| Tier | Tier 1 to 4 (section 2.11). |
| Status | The glyph word: Surging, Heating or Monitoring (section 2.13). |
| Score | Fit plus Timing (section 2.10). |
| Last | The date of the newest result, or "today". |
| Scored this morning | The subline. True: the carry and the rescore run at 06:30 UTC every morning (section 3.5). |
| Invite teammates | Goes to the Team page. |
A.3 The drawer and the account brief
| Field | What it is |
|---|---|
| Tier and status chip | The tier number with its status word. |
| Glyph word chip | Surging, Heating or Monitoring. |
| Window chip | Next 30, 90 or 120 days, or Beyond 120 days (section 5.1). |
| Industry chip | The industry on file. |
| Recommended action | A fixed sentence per tier. Tier 1: reach out this week, opening with the newest event. Tier 2: develop the relationship. Tiers 3 and 4: monitor. |
| Why this score | The card built from account.why (section 5.4). Its head reads "Fit, evidence and timing, out of 85." (or 100 for a workspace with no band). |
| The sentence | why.headline: the score, the band, the parts at full marks, and the points lost per part. On a dataset copy older than the block it reads "We do not have a plain summary for this account yet. These are the parts of the score, as the engine records them." instead. |
| Fit | The group row, earned out of 15, then one row each for the size band, evidence breadth and profile completeness. |
| Timing | The group row, earned out of 25, then the one timing row, whose line of detail is the basis: the lead time estimate in months, or "scaled from the volume probability". |
| A factor row | The part in client words, the engine's own label under it, the line of detail, then "earned of available" and either "full marks" or "N short". |
| Score | The double ruled foot: the account's score out of its maximum. The rows above add to exactly this. The points beside the results in the timeline are a different number and are never added up (section 2.16). |
| What would move it up | why.lift.text, on any account below Tier 1: the points needed for the next band, and the part with the most room. Absent on Tier 1. |
| Segment | SMB, Mid-market or Enterprise by headcount, then headquarters, then the revenue range. |
| Revenue | The company's revenue range. It says "Not known" when we hold no figure. Labelled "Ownership" until this release, which was the wrong word for it. |
| Evidence | The count of observations listed (at most 8) and the account's confidence. |
| Signal timeline | Each result: date, what we found, the excerpt when there is one, evidence area, channel, confidence, points, and Source as a link, or "no link on file". Newest first, at most 8, in the drawer and on the brief alike. Arriving from a desk row highlights that result and scrolls to it. |
| Download CSV, Download JSON | The lead as a file. Any member (section 8.1). |
| Send to CRM | Pushes the lead to the workspace webhook. Admins and contributors. Shown to everyone, and grey when it cannot be used, with the reason printed as a visible line under it and tied to it by aria-describedby, not only as a hover title: "No webhook set. Set your CRM webhook on the Team page." with a link to Team for an admin, "No webhook set. An admin sets it on the Team page." for everyone else, or "Only an admin or a contributor can send." for a viewer (section 8.3). |
| Good lead, Bad lead | Your verdict on the company, with one or more reasons and a why of up to 240 characters, and the team tally beside it. The picker shows four chips under Good lead and six under Bad lead, nine codes in all (section 7.1). |
| Signal mix | Results counted by evidence area, as bars. |
| Open the full brief | Goes to the brief page. |
| Rate on the desk | Goes to the Signal desk. |
A.4 Signal desk
| Field | What it is |
|---|---|
| N sources, M results in the window | The count of signal types seen and of results in your view. |
| Results to review | The 12 newest results across your accounts. |
| Good lead, Bad lead | Your verdict on the company the result belongs to. A reason picker (four chips under Good lead, six under Bad lead, nine codes in all, pick one or several) and a why of up to 240 characters open under the line; the line then shows your verdict and the team tally (section 7.1). |
| Source | A signal type and its evidence area. Not a place we read (section 2.1). |
| What it yields | The catalog's description of the signal type. |
| Status | "Last result <date>" for that signal type in your workspace, or "No results yet". Green only inside seven days (section 3.6). |
| Results | How many results of that type are in your view. |
| Off chip | A kind of signal switched off on Your signals: the row is dim and its results do not count. In the plain case an off kind is absent from this table, because the rows are built from the results that survive the drop (section 6.5). |
| Manage on Your signals | The link in the card header to the Your signals page (A.9). |
| Your value | Your 1 to 5 for that signal type, a why of up to 280 characters, and the team average. |
A.5 Library
| Field | What it is |
|---|---|
| Categories | The count of categories. |
| Signals in the library | The count of signals. |
| In your set | Signals not excluded by your workspace. |
| Data sources | The count of source cards (section 2.1). |
| Graded for | The first industry in your approved ICP, or the industry set on your workspace when the ICP names none, or a note that neither has one. |
| Category card | Name, grade, synopsis, how many signals and sources feed it. Opens to its domain, its signals and its sources. |
| Signal card | Name, grade, state (In your set, Added by you, Modified, Excluded), chain grade, evidence tier, and "Below the bar" when it did not qualify. |
| The causal chain | Trigger, mechanism, predictable next step, and the weakest link. |
| Where we watch for it | One row per chain: source, its library status (verified, proxy, parked), threshold, the problem it feeds, lead time, shelf life, forcing or suggestive. |
| Chips | Chain grade, evidence tier, discoverability tier, business function, buyer, validation score out of 5, monitoring source. |
| Your set | Keep in set or Exclude. Admins and contributors. Does not change the queue today (section 13); the switches on Your signals and Sources do (sections 6.5 and 6.6). The note under the buttons says so. |
| Data source card | Kind, cadence, cost, where, and the signals it feeds. |
A.6 ICP
| Field | What it is |
|---|---|
| Name, version, updated | The display name, the ICP version, and the build date of the view. |
| Who we are looking for | The statement, and who owns it. |
| The attributes that score fit | Size band, signal volume, evidence, monitoring, each with a weight word. |
| Size bands | SMB, Mid-market, Enterprise and how each is treated. |
| Targeting rules | Boosts, down ranks and excludes, each marked template or your workspace. Shown, not applied (section 6.1). |
| Exclusions | What is left out of every view. |
| Your signals | A button beside Edit to the Your signals page (A.9). |
A.7 Team
| Field | What it is |
|---|---|
| Invite a teammate | Admins only. Work email and role. The link works for 14 days, and one live link exists per email. If the email could not be sent, the link is shown so you can pass it on. |
| Members | Name, email, role. Admins see a role picker on everyone but themselves. |
| Pending invites | Admins only. Email, role, sent date, expiry, and whether it was emailed or shared by hand. Admins can revoke. |
| Gold owner | The one account that cannot be removed without a handover. |
| Workspace settings | Admins only. The switch "Members can see the ICP" (section 6.9) and the CRM webhook block: the url field, Save (which shows the secret once), Test, Remove, and the last push line (section 8.3). Everything on the card is disabled in a read only workspace. |
A.8 Guide, Discovery, Workshop and status
| Screen | What it is |
|---|---|
| Guide | The user guide, one chapter per screen, at /app/guide inside the app. The manual and the troubleshooting page sit beside it at /app/manual and /app/troubleshooting. All three are public at https://signals.srv1195619.hstgr.cloud/help with no sign in. |
| Discovery | The optional deep discovery questionnaire, Part 1 and Part 2. Answers save as you type. Off the main path. |
| Workshop | Where your answers and the desk's drafts are compared and an admin decides. Optional. |
| Status | https://signals.srv1195619.hstgr.cloud/status, no sign in needed. Normal, delayed, or a note about an incident. |
| Live data delayed | A band on any page while the database is not answering. You are seeing the last good copy. |
A.9 Your signals
| Field | What it is |
|---|---|
| Signals on, Signals off, Categories, Results in your queue | Kinds of event on, kinds off, the count of categories, and the results in your current view added up across the kinds that are on. |
| Your profile is saved | The band shown when you arrive from the setup flow, with a Skip to your queue link. Everything is on to start. |
| Search | Narrows the rows to kinds whose title contains your word. |
| Category header | The evidence area's name, "N of M on", and for admins and contributors All on and All off. |
| Signal row | Title, the what line, the catalog tier chip (T1 to T3, the signal's value, not the score tier), the weight chip (the points of section 2.16), the results count, and the switch. Kinds with results come first; the rest sit behind "Show the other N". |
| The switch | A filled square reading ON, or an empty outline square for off. Admins and contributors flip it; viewers see it disabled with "Your admin or a contributor sets these". Off drops that kind before scoring for your workspace only (section 6.5). |
| Foot line | "Off means the desk stops counting that kind of event for your workspace. Nothing is deleted; switch it back on any time." |
A.10 Sources
| Field | What it is |
|---|---|
| The tiles | Four: Channels on, Off, Results in your queue, and Last result (the newest date from any channel that is on, or "None yet"). |
| What Axsys collects for you | One ruled row per channel: name, what it reads, how often it runs, Show the N feeds, the Library bucket chip, last result, results in your queue (or not counted when off), and the switch. |
| Show the N feeds | Opens the list of feeds inside the channel. Display only; there is no switch per feed (section 6.6). |
| Last result | The date of the newest observation from this channel among your companies. |
| Results, Not counted | Observations from this channel in your current view; when the channel is off, every observation from it on a company inside your universe filters. |
| The switch | A filled square reading ON, or an empty outline square for off. Admins flip it; everyone else sees it disabled with "Only an admin can change this." Off drops that channel before scoring for your workspace only (section 6.6). |
| In the library, not collected yet | The Library buckets no collector reads yet. Read only. |
| Next: Sources | The link on Your signals that brings a new workspace here as the last setup step. |
| Add your own source | Name, url, industry, notes, and a tick for a site behind a login with a line saying what kind of login it is. Never a password. Saves as queued (section 6.7). |
| Import a CSV | Up to 500 rows with a header of name, url, industry, notes, behind_login and login_note. Answers a count and the rejected rows with a reason each (section 6.7). |
| Start with the (industry) set | The band offering the sources Jeff and Tommy picked for your industry. They arrive queued (section 6.7). |
| What produced results | Per channel, over 7 or 60 days: rank, results, accounts, the last date, and a note when there were none or the channel is off (section 6.8). |
| Queued, not collected yet | The state of every source a workspace adds. Written down, read by nothing. |
| Slow down a little | The three write cards share one cap of 60 an hour for the whole workspace: adding one, importing a file and applying a starter set together (section 6.7). |
A.11 Health
| Field | What it is |
|---|---|
| 1 day, 7 days, 30 days | The window. Seven days when you arrive. |
| The run history only goes back 14 days, so this window shows the last 14 days, not 30 days. | The line under the chips when the window asked for is longer than the run history we hold. Every count and sentence on the page is then written against the shorter window (section 3.6). |
| Collectors, Ran, Channels with results, Failed | How many collectors we run, how many ran, how many channels landed a result for your companies, how many had a failed run. The third tile counts channels rather than rows, and reads "not known yet" when your results could not be read. |
| The row | The collector's own plain name, one sentence, the last run stamp, the Channel line naming the channels it feeds, and the code chip (Appendix B). Our name for the automation is not shown anywhere on the page. |
| 2 of those runs failed | A row says its failures out loud, even when its newest run worked, so the Failed tile always has rows behind it. |
| We ran out of time before we got to this one. Reload in a moment. | The 20 second budget ran out before that row was read. The rest of the page is still true; reload and it fills in (section 3.6). |
| Health needs the n8n key on the server. | The box has no automation key. Nothing is wrong with the workspace (section 3.6). |
| Health could not reach n8n right now. | The automation server did not answer. Reload in a few minutes. |
| Rows are per collector until feed level tracking lands; then per feed. | The foot line. It says the grain out loud. |
A.12 Ask for access
| Field | What it is |
|---|---|
| Name, work email, company, what you sell | The four fields on the public form at https://signals.srv1195619.hstgr.cloud/request. No session, no account, nothing created (section 1.4). |
| Thanks. We will write back within two working days. | The answer, every time the form is accepted. |
| Slow down | Three requests an hour from one network address, or three a day for one email. |
Appendix B.Reason codes
One code per collector run, one short sentence per code. The Health page shows the sentence and puts the code in a small chip beside it, so a person can look it up here. This table, the dictionary in the code and the file docs/signals/reason-codes-2026-09-05.md say the same thing. The sentences are to be confirmed at the 9/10 standup. Most codes describe a run; five of them describe the row instead, because there was no run to read.
A collector fired when all three of these are true: it ran, it found something, and what it found matched one of your companies. All three, or it did not fire.
| Code | The sentence | Whose problem |
|---|---|---|
ran_found | It ran and found results for one of your companies. | Not a problem |
ran_empty | It ran, but the sources had nothing new. | Not a problem |
ran_no_match | It ran and found things, but none were about your companies. | Not a problem |
did_not_run | It did not run in this window. | Ours |
failed_vendor | It ran, but the site or service it reads from gave an error. | Ours to chase, often theirs to fix |
failed_auth | It could not sign in to the service. The key or password needs a fix. | Ours |
failed_network | It could not reach the service. The connection dropped. | Often fixes itself |
stalled | It started but never finished. | Ours |
paywall | The service wants money before it will answer. | Ours |
url_changed | The address it reads from has moved. | Ours |
expired_card | The card on file for this service has expired. | Ours |
unknown | We could not tell what happened. | Ours to look at |
Two in between states, because the automation server alone cannot say more:
| Code | The sentence |
|---|---|
ran | It ran. Whether it found anything for you comes from your workspace's results. |
running | It is running right now. |
Five states about the row itself, set before there is any run to read. They carry no counts and no last run stamp, they are quiet states rather than faults, and the page gives them a plain grey chip. Each one describes the row it sits on and never the whole channel, because two collectors on one channel can be in two different states:
| Code | The sentence | Whose problem |
|---|---|---|
not_automated | We load this one by hand rather than on a schedule, so there is nothing to watch here yet. | Not a problem |
not_client_facing | We mostly use this one to fill in the numbers on your accounts. Very few of its finds reach your queue as results. | Not a problem |
not_collecting | This one is not collecting yet, so nothing from it has reached you. | Ours |
not_found | The automation behind this one is not switched on yet. | Ours |
not_checked | We ran out of time before we got to this one. Reload in a moment. | Nobody's; reload |
When you see each one. not_automated: the registry names a script or a load done by hand, so there is no run history to read; two rows read this way today, the one off web sweep and the SBA batch load. not_client_facing: the row fills in the numbers on your accounts in the background rather than putting results in your queue; one row today, the financial profile fill. not_collecting: that collector has never collected anything; one row today, the OSHA inspections feed, whose address does not exist. not_found: the registry names a workflow the automation server did not list, which happens when a collector is renamed, switched off or never built. not_checked: the crawl spent its 20 second budget before it got to that row, so the row was never read; the rest of the page is still true and a reload fills it in.
What a row is titled. The collector's own client safe name: News sweep, Hiring and workforce sweep, Austin permits pull, and so on. Our workflow name and its id are not in the answer at all. Every collector has a name of its own, so no two of the fourteen rows read the same. The channels a collector feeds are named on the Channel line under its sentence, in the same words the Sources page uses.
How a run becomes a code. Health reads the automation server's executions for each collector inside the window.
| What the run says | Code | Why |
|---|---|---|
| success | ran | The server knows only that it finished. Your results say whether anything landed. |
| error, crashed | failed_vendor | Unless the words below make it more exact. |
| canceled | did_not_run | Someone stopped it, so it did no work. |
| waiting, running, new, under 30 minutes old | running | It is still going. |
| waiting, running, new, 30 minutes or older | stalled | It started and never finished. |
| no run at all in the window | did_not_run | Nothing started. |
Words in the error text make a failure exact, checked in this order: sign in words (unauthorized, forbidden, 401, 403, api key, credential, token, permission) give failed_auth; money words (paywall, payment, 402, subscription, quota, credits, plan limit, billing) give paywall; connection words (timeout, timed out, econnreset, enotfound, dns, unreachable and their friends) give failed_network. Anything else stays failed_vendor. The run list does not carry the error text unless the app asks for the whole run, and the app keeps no workflow name from a run, so most failures land on failed_vendor today.
**From ran to a verdict.** A collector belongs to one or more channels through the registry (section 6.6). If any of its channels has a result for your companies inside the window, the row becomes ran_found and the sentence names the date. If none does, it becomes ran_no_match. Honest limit: from your results we cannot tell ran_empty (the sources had nothing) from ran_no_match (they had things, none about you), so the app always uses ran_no_match for "it ran, nothing landed for you".
When a collector ran several times in the window, the row shows the newest finished run's code, and the counts on the row cover every run in it.
After feed level tracking. Each feed inside a channel will carry its own last run, item count and error, so ran_empty becomes real, ran_no_match becomes exact, url_changed and expired_card can be produced from a feed's own error, and a Health row can name the one newspaper that died inside a channel that otherwise looks healthy. The rows go one per channel first, then one per feed under the channel.
End of the manual.