oficina / memoria Public

Clone
git clone https://amadan.net/oficina/memoria

Plain git — no account needed to clone.

Download

Download this file

1package memoria
2
3import "time"
4
5// Connector is one configured source outside the suite.
6//
7// The credential lives here, sealed under its own HKDF purpose, so a
8// disclosure of the chunk store does not also yield the key to the source
9// those chunks came from — the spec's §3.5, which calls least-privilege
10// connector credentials a requirement rather than a nicety.
11type Connector struct {
12 ID int64
13 // Kind is "notion". One row per kind.
14 Kind string `gorm:"uniqueIndex;not null"`
15 // SealedToken is the integration token. Never rendered back, not even
16 // masked: a masked secret is still a secret in the DOM.
17 SealedToken []byte `gorm:"not null"`
18 // WorkspacePrint is a keyed fingerprint of the workspace the token
19 // belongs to, so two connectors pointing at one workspace are
20 // detectable without storing which workspace that is.
21 WorkspacePrint string
22 LastVerified *time.Time
23 CreatedAt time.Time
24 UpdatedAt time.Time
25}
26
27// SyncRun is one import, and the row that makes it resumable.
28type SyncRun struct {
29 ID int64
30 ConnectorID int64 `gorm:"index;not null"`
31 // State is enumerating | fetching | done | failed | interrupted.
32 State string `gorm:"index;not null"`
33 // Roots is how many top-level pages the integration could see, so
34 // "I expected more than that" is an answerable question.
35 Roots int
36 // Total is -1 until enumeration finishes.
37 //
38 // Not 0. The precedent is handlers.go's chunkCount, which returned 0
39 // on error and made the page assert an absence was real when the app
40 // had merely failed to look. A total that could not be determined is
41 // not a total of zero pages.
42 Total int `gorm:"not null;default:-1"`
43 Fetched int
44 Skipped int
45 Empty int
46 FailedPages int
47 UnreadBlocks int
48 // ErrorCode is a CODE, never a message. Notion's own error bodies
49 // carry content — a 404 quotes the page id and the connection name —
50 // and AGENTS.md forbids content in any error string.
51 ErrorCode string
52 // Heartbeat lets a run wedged inside a LIVE process be reclaimed. A
53 // run killed by the platform sleeping is reclaimed at boot instead,
54 // which is sound by construction rather than by timeout: there can be
55 // no live run at boot.
56 Heartbeat *time.Time
57 StartedAt time.Time
58 FinishedAt *time.Time
59}
60
61// SourcePage is the ledger: one row per page a connector has seen.
62//
63// Keyed per CONNECTOR and not per run, which is the whole reason a second
64// run resumes instead of restarting.
65type SourcePage struct {
66 ID int64
67 ConnectorID int64 `gorm:"index;not null"`
68 // PagePrint is the keyed page id, used to find this row.
69 //
70 // It does NOT join to a Document's ExternalID, though a comment here
71 // used to say so: both are HMACs, under different purposes, of
72 // different inputs. The link to the document is DocumentID below.
73 PagePrint string `gorm:"index;not null"`
74 // SealedPageID is the id itself, sealed and REVERSIBLE.
75 //
76 // Both columns exist because an earlier design stored only the
77 // fingerprint, and seal.Fingerprint is HMAC-SHA256: a resumed run
78 // would have held 1,930 fingerprints and no id to fetch with. Found
79 // by a design review before any of it was written.
80 SealedPageID []byte `gorm:"not null"`
81 // SealedPath is the ancestry as enumeration saw it. PathPrint lets a
82 // move — or an ancestor rename — be detected without opening the row.
83 SealedPath []byte
84 PathPrint string
85 // SeenEdited is what the last enumeration saw; IngestedEdited is what
86 // memoria actually ingested. Two columns, because one column compares
87 // against itself and therefore skips every edit.
88 SeenEdited string
89 IngestedEdited string
90 // IngestedPath is the path print as of the last successful ingest.
91 // A row is up to date only when BOTH the edit time and the ancestry
92 // match what was ingested — an ancestor rename moves the second
93 // without moving the first.
94 IngestedPath string
95 // State is pending | fetched | empty | failed.
96 State string `gorm:"index;not null;default:'pending'"`
97 ErrorCode string
98 // LastSeen is written on every enumeration, so "no longer in the
99 // source" stays answerable without a later migration. memoria does
100 // not delete on absence; it does not follow that it should be unable
101 // to say what has gone.
102 LastSeen time.Time
103 DocumentID int64
104 CreatedAt time.Time
105 UpdatedAt time.Time
106}
107